I'm currently working with the MSP430G2553, which is coded in C.
For some reason I seem to be awful at coding basic For and While loops, and I can't figure out how to make a While loop take longer to complete after every iteration.
Basically, I have an LED blinking at 100ms on startup.
When I hold a button, I want to make the LED blink slower and slower the longer I hold the button.
When I let go, the LED should keep its slowed-down blinking rate.
Then, a second button will reset the LED blink-rate back to 100ms.
Right now, I'm able to slow down the LED blinking when I hold the button, but it does not keep going slower. Honestly, I'm not sure how to go about doing this so I made an account here and posted.
for(;;) //loop forever
{
if((P1IN & BIT3)==BIT3) //if button is not pressed
{
i = 0;
a = 4000; //At 10000, 4 cycles per second, or 250ms delay. 4000 cycles = 100ms or 10Hz delay.
P1OUT ^= BIT0 + BIT6; //two LEDs
while(i < a) //delays LED blinking until while-loop is complete.
{
i = i + 1;
}
}
else if((P1IN & BIT3)!=BIT3) //if button is pressed
{
i = 0;
a = 10000;
P1OUT ^= BIT0 + BIT6;
while(i < a) //delays LED blinking until while-loop is complete.
{
a = a + 2;
i = i + 1;
}
}
}
You would need to keep a "global" ( outside of the for scope ) delay counter to keep track of the last button press, or the delay
int button1Pressed = 0; // "global" flag
for(;;)
{
if((P1IN & BIT3) != BIT3) // if button pressed
{
button1Pressed = 1;
}
if((P1IN & BIT4) != BIT4) // hypothetical button 2 press
{
button1Pressed = 0;
}
int delay = 4000;
if(button1Pressed)
{
delay = 10000;
}
while(delay>0) {
delay = delay - 1;
}
}
Related
I trying to implement a gpio toggle function using the STM32GO uC which can run at max clock speed of 64Mhz. I'm using the timer 16 instance to count ticks and run the interrupt callback function every 8uS.
So every 8us the uC will run the following code
'''code'''
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim16)
{
HAL_NVIC_EnableIRQ(TIM16_IRQn);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
static int count = 0;
if(this_bit == 96) //check if array is over
{
this_bit = 0;
count = 0;
}
++count;
if(CARD_ID[this_bit]) //check if the bit to me modulated is 1
{
if(!(count % 5))
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
}
if (!(count % 50))
{
this_bit = this_bit + 1;
count= 0;
}
}
else
{
if(!(count % 4))
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
}
if (!(count % 50))
{
this_bit= this_bit + 1;
count= 0;
}
}
}
}
'''code'''
If I run this callback function without all of the logic and just a simple gpio toggle, I get the proper 8us toggle waveform on the oscilloscope.
But as soon as include this above mention logic the gpio toggle period increases to a maximum of 16uS.
This tells me the delay has to do with the excess code lines present in the ISR.
Is there a way to optimize this function so that i get the desired gpio toggle at 8uS with all this logic still in place?
The logic is to implement a FSK modulation on a carrier wave of 125khz, hence the frequency of gpio toggle needs to change for a binary '1' and the binary '0'.
The CARD_ID array just holds the sequence of the binary data which is used to modulate the carrier.
Thanks
I want to interface a keypad in stm32 l053r8 with timer interrupt. I have a SysTick_Handler function which I am handling there the switch debouncing of push buttons and every time the push button counter gets equal to 10 I am using a flag in order to check when the button is pressed. So now I have all the rows of the keypad as input and all the columns of the keypad as output. My idea is
Every timer int, it activates a new column and reads the 4 row inputs
Check if a button flag is "1" and send the appropriate message to the screen.
I have an implementation but it is not working.For example in main function I have a condition that checks if the key1 (expect 1 as output in screen) is pressed but it doesn't do anything. Any advice would be great.
void TIM2_IRQHandler(void) {
if (TIM2->SR & TIM_SR_UIF ) {
//Clear Timer 2 Flag
CLEAR_BIT(TIM2->SR, TIM_SR_UIF);
if (column_counter==4)
column_counter=0;
column_counter++;
keypad_scanning(column_counter); // activate col=1 or 2 or 3 depends on counter.
}
}
void keypad_scanning(uint8_t column_pos) {
switch (column_pos) {
case 1:
SET_BIT(GPIOC->ODR,GPIO_ODR_OD15); // C1 HIGH
CLEAR_BIT(GPIOA->ODR,GPIO_ODR_OD1); // C2 LOW
CLEAR_BIT(GPIOA->ODR,GPIO_ODR_OD4); // C3 LOW
if (flag0.fl.f5 && !(flag0.fl.f6) && !(flag0.fl.f7)) {
key0.fl.f1 = 1; // key 1 is pressed.
}
if (!(flag0.fl.f5) && flag0.fl.f6 && !(flag0.fl.f7)) {
key0.fl.f4 = 1; // key 4 is pressed.
}
if (!(flag0.fl.f5) && !(flag0.fl.f6) && flag0.fl.f7) {
key0.fl.f7 = 1; // key 7 is pressed.
}
break;
case 2:
CLEAR_BIT(GPIOC->ODR,GPIO_ODR_OD15); // C1 LOW
SET_BIT(GPIOA->ODR,GPIO_ODR_OD1); // C2 HIGH
CLEAR_BIT(GPIOA->ODR,GPIO_ODR_OD4); // C3 LOW
if (flag0.fl.f5 && !(flag0.fl.f6) && !(flag0.fl.f7)) {
key0.fl.f2 = 1; // key 2 is pressed.
}
if (!(flag0.fl.f5) && flag0.fl.f6 && !(flag0.fl.f7)) {
key0.fl.f5 = 1; // key 5 is pressed.
}
if (!(flag0.fl.f5) && !(flag0.fl.f6) && flag0.fl.f7) {
key0.fl.f8 = 1; // key 8 is pressed.
}
break;
case 3:
CLEAR_BIT(GPIOC->ODR,GPIO_ODR_OD15); // C1 LOW
CLEAR_BIT(GPIOA->ODR,GPIO_ODR_OD1); // C2 LOW
SET_BIT(GPIOA->ODR,GPIO_ODR_OD4); // C3 HIGH
if (flag0.fl.f5 && !(flag0.fl.f6) && !(flag0.fl.f7)) {
key0.fl.f3 = 1; // key 3 is pressed.
}
if (!(flag0.fl.f5) && flag0.fl.f6 && !(flag0.fl.f7)) {
key0.fl.f6 = 1; // key 6 is pressed.
}
if (!(flag0.fl.f5) && !(flag0.fl.f6) && flag0.fl.f7) {
key0.fl.f9 = 1; // key 9 is pressed.
}
break;
}
}
void SysTick_Handler(void) {
//------------------------------
//key 1 sampling ( ROW 1 FLAG)
if(!flag0.fl.f5) {
if(!KEY1_READ()) {
if(key1_counter == 10)
flag0.fl.f5 = 1; // R1 is HIGH
key1_counter = 0;
} else {
if(key1_counter < 10) //10 ms sampling
key1_counter ++;
}
}
//------------------------------
//------------------------------
//key 2 sampling (ROW 2 FLAG)
if(!flag0.fl.f6) {
if(!KEY2_READ()) {
if(key2_counter == 10)
flag0.fl.f6 = 1; // R2 is HIGH
key2_counter = 0;
} else {
if(key2_counter < 10) //10 ms sampling
key2_counter ++;
}
}
//------------------------------
//------------------------------
//key 3 sampling (ROW 3 FLAG)
if(!flag0.fl.f7) {
if(!KEY3_READ()) {
if(key3_counter == 10)
flag0.fl.f7 = 1; // R3 is HIGH
key3_counter = 0;
} else {
if(key3_counter < 10) //10 ms sampling
key3_counter ++;
}
}
//------------------------------
}
First, your title says 4x4 but the code appears to be for 3x3.
Next, an electrical signal can propagate through a key matrix almost instantaneously. You should do do every column one straight after the other, you don't need a timer to do that. Just do: column high, read row, column low, next column high, etc.
After that, you only read the state of the key if it is not already pressed. You try to debounce the rising edge, but once the key is pressed it seems to stay pressed for ever, you never look for the falling edge when the key is released. Falling edges can bounce too, so you need to have a count there too.
Also, you are checking for the state where only one row is active with if(x && !y && !z). What if the user presses more than one button at a time? For each flag you only need to check for one input.
These points won't fix everything, but hopefully will get you further along the way!
I suspect the following code to cause you some problems.
if(!KEY1_READ()){
if(key1_counter == 10)
What are the chances that you will release the button when counter is exactly 10?
You seem to want an on-release event, so I would write the scanning code like so:
if (KEY1_READ()) {
key1_counter++;
} else {
if (key1_counter > 10) {
flag0.fl.f5 = 1;
}
key1_counter = 0;
}
Don't forget to reset the flag after you're done processing it.
I found the solution for that. First of all thank all of you that gave me an advice and post a question. I used the timer (TIM2) and created an interrupt every 1ms. For each interrupt I was giving in the 3 column, which was my output ports, a sequence of binary numbers, while having all my input ports(rows) grounded. First sequence was 1 0 0, second 0 1 0 and third 0 0 1. After that sequence I was reading the inputs(rows) in order to detect which one was set at high("1"), with that I was able to detect which key was pressed by rasing a flag. All of that is similar to the code I 've posted but I used different register for make the outputs(columns) goes from high(logic "1") to ground(logic "0"), that is the BSRR register. For detection if a button is pressed I use the debounce method.
I'm currently working on a mini project to have my pushbutton toggle a blinking LED, meaning: when I press the button, I want the LED to keep blinking until I press the button again.
I managed to toggle the LED without blinking (when I press the button, the LED lights up, and when I press the button again, the LED switches off, but no blinking).
I've appended my code below, and my logic is based on tracking the current button state and the previous button state, which I think is the correct logic (but if I'm wrong please criticise/correct me!!) to cause a change in LED output state, so I'm not sure what's wrong with my thinking/code. The problem I have now is that the LED will only blink twice (according to the line of code I've written in void loop) but it does not keep blinking forever until I want it to stop (what can I do to execute this?)
const int ledPin = 8;
const int buttonPin = 7;
int buttonState;
int ledState = HIGH;
int lastbuttonState = LOW;
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState != lastbuttonState) {
if (ledState == HIGH) {
digitalWrite(ledPin, HIGH);
delay(200);
digitalWrite(ledPin, LOW);
delay(200);
} else {
digitalWrite(ledPin, LOW);
}
}
lastbuttonState = buttonState;
}
Will be extremely grateful if anyone can point out any mistakes!! Thank you!
The most important idea here is use the button to toggle blinkState. When the state indicate the LED should be blinking, use millis() get the current time and calculate when ledState should be toggled. When enough time has passed, calculate the next time, toggle ledState, and loop back.
Note I am using the bounce2 library to debounce the button. You could do button debouncing with timer as well.
#include <Bounce2.h>
#define LED_PIN 13
#define BUTTON_PIN 2
#define DEBOUNCE_DELAY 100
#define BLINK_DELAY 200
uint32_t nextMillis = 0;
bool blinkState = 0, ledState = 0, previousLedState = 0;
Bounce b = Bounce();
void setup() {
Serial.begin(9600);
delay(1000);
pinMode(LED_PIN, OUTPUT);
b.attach(BUTTON_PIN, INPUT_PULLUP);
b.interval(DEBOUNCE_DELAY);
}
void loop() {
b.update();
if(b.fell()){
blinkState = !blinkState;
}
if (blinkState){
if (millis() > nextMillis){
nextMillis = millis() + BLINK_DELAY;
ledState = !ledState;
}
} else {
ledState = 0;
}
//only write to pin if ledState changed
if (ledState != previousLedState){
digitalWrite(LED_PIN, ledState);
previousLedState = ledState;
}
}
This part
(buttonState != lastbuttonState)
is logically incorrect as the state of the push button will immediately become false when you press the push button once and release it. The last state of the push button would be FALSE as per the logic that you have written.
Another way could be to implement would be to increment an counter variable on pressing the push button once and start blinking when the counter value is odd and stop blinking when the counter value is even.
const int ledPin = 8;
const int buttonPin = 7;
int buttonState=HIGH,reading;
int ledState = LOW;
int lastbuttonState = HIGH,icounter;
unsigned long latchMillis,lastDebounceTime;
void setup()
{
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}
void loop()
{
unsigned long blinkdelay = 1000,debounceDelay=1;
/***Debounce logic for the input ***/
reading = digitalRead(buttonPin); //Check for the change in PB
if (reading != lastbuttonState)
{
lastDebounceTime = millis(); // reset the debouncing timer
}
lastbuttonState = reading; //Update previous button state
if ((millis()-lastDebounceTime) > debounceDelay) //If debounce has elapsed then accept the input
{
if (buttonState != lastbuttonState)
{
if (buttonState == LOW)
{
icounter = icounter +1; //Increment counter on every rising edge of PB
latchMillis = millis(); //Latch the current millis
}
buttonState = lastbuttonState;
}
}
if ((icounter%2)!= 0)
{
if ((millis() - latchMillis) > blinkdelay)
{
ledState = !ledState;
latchMillis = millis();
digitalWrite(ledPin,ledState);
}
}
else
{
digitalWrite(ledPin, LOW);
}
}
`
To turn on the led the switch is to be pressed for 2 times,turn off the led the switch is to be pressed 3 times within 10 second?can any one explain the logic how to implement it?
I checked the status of a switch in delay function, but it's not working
#include<reg51.h>
void delay_ms(unsigned int );
int count=0;
sbit sw=P2^0;
sbit led=P1^0;
main()
{
while(1)
{
if(sw==0)
{
delay_ms(10000);
}
}
}
void delay_ms(unsigned int i)
{
int j;
for(i;i>0;i--)
for(j=122;j>0;j--)
{
if(sw==0)
{
while(sw==0);
count++;
if(count==2)
led=1;
if(count==3)
led=0;
}
}
}
expected result- switch pressed 2 times should turn on led and
switch pressed 3 times should turn off led (within 10 sec)
actual result- switch pressed 2 times should turn on led and
switch pressed 3 times should turn off led (but works without any time limit)
An alternative and more flexible solution (in an application where you might need to do other work concurrently), is to timestamp the switch events and compare the current event time with the previous timestamps.
Given a regular time source (assuming the standard clock() here but the logic is valid regardless) :
#include <time.h>
#include <string.h> // for memset()
#include <stdbool.h>
bool isSwitchEvent()
{
sbit sw = P2^0 ;
bit current_sw = sw ;
static bit previous_sw = sw ;
// NOTE: Ignoring switch bounce issues - different question
// Switch event when state *changed* to 1->0...
bool switch_event = (current_sw == 0 && previous_sw == 1) ;
previous_sw = current_sw ;
return switch_event ;
}
#define SWITCH_PERIOD CLOCKS_PER_SEC * 10
int main()
{
sbit led = P1^0;
// Initialise so that first switch event is guaranteed to be at
// least then 10 seconds later than the initial timestamps.
clock_t switch_timestamp[3] = {-SWITCH_PERIOD,
-SWITCH_PERIOD,
-SWITCH_PERIOD } ;
unsigned i = 0 ;
bit led_state = 0 ;
bool change = false ;
for(;;)
{
// On switch event...
if( isSwitchEvent() )
{
// Timestamp event
switch_timestamp[i] = clock() ;
// If LED off, and previous event was less
// than 10 seconds ago...
if( led_state = 0 &&
switch_timestamp[i] - switch_timestamp[(i+2)%3] < SWITCH_PERIOD )
{
// LED on
led_state = 1 ;
change = true ;
}
// else if LED on, and previous two events were less
// than 10 seconds ago...
else if( led_state = 1 &&
switch_timestamp[i] - switch_timestamp[(i+1)%3] < SWITCH_PERIOD )
{
// LED off
led_state = 0 ;
change = true ;
}
// If LED state change...
if( change )
{
// Set output to the prevailing LED state
led = led_state ;
// Make timestamps older that SWITCH_PERIOD so
// previous events are not to be counted
// for next LED state change.
switch_timestamp[0] = clock() - SWITCH_PERIOD ;
switch_timestamp[1] = switch_timestamp[0] ;
switch_timestamp[2] = switch_timestamp[0] ;
// Next timestamp
i++ ;
i %= 3 ;
}
}
// You can do other work here (so long as
// it does not take so long as to miss a
// switch event).
}
return 0 ;
}
The issue is that you are not providing any debounce for your switch. Also where is count being initialized? I don't see it.
You need to have a delay when you detect the switch closed because it will "bounce" open and closed many times in the first few milliseconds. I would delay for at least 10mS before checking to see if the switch has been opened and then you can change your count.
UPDATE BASED ON OP COMMENTS:
Well again, this would only work in simulation. Switches are not that good. But I do see your issue: You don't reset count in your main(). Try:
main()
{
while(1)
{
count = 0;
if(sw==0)
{
delay_ms(10000);
}
}
}
The microcontroller is AVR and the processor in it is ATMEGA8. I wrote a piece that followed the black color. It is like :
#include<avr/io.h>
#include<util/delay.h>
int main()
{
int rs,ls; // denotes the right sensor and left sensor respectively
DDRC=0x00; // DENOTES THAT WE TAKE INPUT FROM THE SENSER
DDRB=0xFF; // DENOTES THAT PORT IS MEANT FOR THE OUTPUT FROM THE MOTOR
while(1) {
ls=PINC&0b0000001; // last bit on
rs=PINC&0b0001000; // 1st bit on
if((ls==0b0000001)&(rs==0b0001000))
PORTB=0b00010010; // forward
if((ls==0b0000001)&(rs==0b0000000))
PORTB=0b00000010; // right
if( (ls==0b0000000) & (rs==0b0001000))
PORTB=0b00010000; // left
if((ls==0b0000000)&(rs==0b0000000) )
PORTB=0b00010010; // stop
}
}
I am trying to write for the edge avoider. It has the same sensors that detect the black color. But now those sensers have to avoid a pit while moving on the table. I am unable to decide as to how i can do this.
NOTE : Sensor is able to detect the pit if there is nothing beneath it. But how do I am having problem writing code.
There can be many solutions for Edge Avoider. One implementation I have seen is -
Explanation -
If none (left & right) is black (black = edge, white = table surface), you can keep moving forward.
If any/both are black, you need to back off a little (CAUTION : This is tricky, in backing also, you may end up falling), and then change direction.
You need to experiment with delays, to get appropriate working.
These are the values needed below (I had omitted them before, because they are dependent on configuration)-
int move_backward = 0b00000110;
int right_turn = 0b00001010;
int move_forward = 0b00001001;
int left_turn = 0b00000101;
int left_sensor_on = 0b0010000;
int right_sensor_on = 0b0100000;
int left_sensor_off = 0b0000000;
int right_sensor_off = 0b0000000;
The below code should go inside while (1)
left_sensor = (PINC & 0b0000001); // This depends upon your configuration
right_sensor = (PINC & 0b0001000); // So I have used, the one from your code
if ((left_sensor==left_sensor_off) & (right_sensor==right_sensor_off))
{
PORTB = move_backward; //move backward
_delay_ms(50);
PORTB=right_turn; //take a right turn
_delay_ms(30);
left_sensor = 0;
right_sensor = 0;
}
if ((left_sensor==left_sensor_on) & (right_sensor==right_sensor_on))
{
PORTB = move_forward; //move forward
left_sensor = 0;
right_sensor = 0;
}
if ((left_sensor==left_sensor_off) & (right_sensor==right_sensor_on))
{
PORTB = move_backward;
_delay_ms(50);
PORTB = right_turn;
_delay_ms(30);
left_sensor = 0;
right_sensor = 0;
}
if ((left_sensor==left_sensor_on) & (right_sensor==right_sensor_off))
{
PORTB = move_backward;
_delay_ms(50);
PORTB = left_turn;
_delay_ms(30);
left_sensor = 0;
right_sensor = 0;
}