Help identifying the issue in this C code [STM32] - Page 1
Forum section: electronics / general

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 24, 2018, 11:15:08 pm
content: So far, this is all I have in the main loop.while (1){check_speed_command();}void check_speed_command() {//STARTif(Rx_Data== 0x33 && start_status == 0) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);HAL_Delay(100);command_dutyC = 5;real_dutyCycle = 8*command_dutyC;start_status=1;Rx_Data=0;}//SPEED UPelse if (Rx_Data==0x32 && start_status==1){last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC+5;real_dutyCycle = 8*command_dutyC;Rx_Data=0;}//SPEED DOWNelse if (Rx_Data==0x31 && start_status==1){last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC-5;real_dutyCycle = 8*command_dutyC;Rx_Data=0;}//PAUSEelse if (Rx_Data==0x36 && start_status==1 && resume==0){last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;Rx_Data=0;resume=1;}//RESUMEelse if (Rx_Data== 0x33 && start_status == 1 && resume==1){command_dutyC = last_command_D;real_dutyCycle = 8*command_dutyC;resume=0;Rx_Data=0;}//STOPelse if (Rx_Data== 0x36 && start_status == 1 && resume==1){last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;resume=0;start_status = 0;Rx_Data=0;}}The problem is this:When the PAUSE condition is true, I expect to clear the Rx variable, i.e, Rx_Data=0;But this is not happening because the STOP condition is executing at the same time than PAUSE. As I cleared the Rx variable during PAUSE condition, the STOP condition should not execute until I modify the Rx variable again.The code does what I want it to do, except for the PAUSE and STOP conditions.Additional Info: I have a routine executing every 30 msvoid HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {// This callback is automatically called by the HAL on the UEV eventif(htim->Instance == TIM6) {if(real_dutyCycle >= last_dutyC && actual_dutyC < real_dutyCycle && actual_dutyC < 800){actual_dutyC++;htim1.Instance->CCR1 = actual_dutyC;}else if(real_dutyCycle <= last_dutyC && actual_dutyC > real_dutyCycle && actual_dutyC > 0){actual_dutyC--;htim1.Instance->CCR1 = actual_dutyC;}}}

author: SilverSolder
author_rank: Super Contributor
timestamp: October 25, 2018, 01:53:05 am
content: Read up on something called "State Machine" (google it)In your code, you could repurpose your start_status variable to contain all the possible states of your State Machine.start_status = 0 //stoppedstart_status = 1 //cold startstart_status = 2 //speed upstart_status = 3 //speed downstart_status = 4 //pausedstart_status = 5 //resuming (warm start)Then, in all your IF statements, you just check that the right status is active in order to allow it to proceed. Inside the IF statement, you set the correct status.You could read the input in just one place, and set the correct State there.You could even use an enum in C, to describe the state.e.g. enum cur_state {stopped, cold_start, ....You will see the code becoming very clean and maintainable this way!

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 02:26:41 am
content: I haven't spent the time to figure out your problem but...* Please use the code tag to make your post more readable* I believe the logic will be easier if you breakup the IF -THEN-ELSE statements as follows:Code:void main(){while (1) {check_speed_command();}}void check_speed_command(){switch (Rx_Data) {case 0x33: //STARTif (start_status==0) {HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);HAL_Delay(100);command_dutyC = 5;real_dutyCycle = 8*command_dutyC;start_status=1;Rx_Data=0;}break;case 0x32: //SPEED UPif (start_status==1) {last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC+5;real_dutyCycle = 8*command_dutyC;Rx_Data=0;}break;case 0x31: //SPEED DOWNif (start_status==1) {last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC-5;real_dutyCycle = 8*command_dutyC;Rx_Data=0;}break;case 0x36: //PAUSEif (start_status==1 && resume==0) {last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;resume=1;Rx_Data=0;}break;case 0x33: //RESUMEif (start_status==1 && resume==1) {command_dutyC = last_command_D;real_dutyCycle = 8*command_dutyC;resume=0;Rx_Data=0;}break;case 0x36: //STOPif (start_status==1 && resume==1) {last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;resume=0;start_status = 0;Rx_Data=0;}break;}}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){// This callback is automatically called by the HAL on the UEV eventif (htim->Instance == TIM6) {if (real_dutyCycle >= last_dutyC && actual_dutyC < real_dutyCycle && actual_dutyC < 800) {actual_dutyC++;htim1.Instance->CCR1 = actual_dutyC;}else if (real_dutyCycle <= last_dutyC && actual_dutyC > real_dutyCycle && actual_dutyC > 0) {actual_dutyC--;htim1.Instance->CCR1 = actual_dutyC;}}}

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 02:32:49 am
content: One problem is that the Rx_Data value for both the PAUSE and STOP state is 0x36. Is that an error?If not, you will need to merge those two states.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 02:35:40 am
content: Quote from: MarkF on October 25, 2018, 02:32:49 amIt's not an error. Rx_Data value for both PAUSE and STOP is the same, but given under different conditions. But that's the problem I'm having. They have different conditions, but they execute at the same time, when they shouldn't.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 02:40:34 am
content: Quote from: XaviPacheco on October 25, 2018, 02:35:40 amHow do you know which state you should do then?I would change the PAUSE and STOP to different values if at all possible.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 02:45:09 am
content: I haven't given many details of the project, but pause and stop are the same button. Pause is called when pressed first time, and "stop" if pressed second time. So, do you think I should give a different value when the button is pressed the second time?Start and resume have also the same value, and they work okay. The issue is with pause and stop.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 02:48:06 am
content: Would this work for you?Code:case 0x36: //PAUSE and STOPif (start_status==1) {last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;if (resume==1) {resume=0;start_status = 0;Rx_Data=0;} else {resume=1;Rx_Data=0;}}break;Edit: Cleaning up a little

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 02:54:56 am
content: Quote from: MarkF on October 25, 2018, 02:48:06 amI will give it a try and report back. I will first convert my if-else mess into switch case.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 02:58:34 am
content: It should just be a cut and paste.However, note that I messed up my cleanup. I updated my previous post.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 03:15:08 am
content: Quote from: MarkF on October 25, 2018, 02:58:34 amMy compiler just threw an error. It makes sense as I have two cases (start and resume) with the same value. I have to do what you did with stop&resume.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 03:47:01 am
content: The new code is still doing the exactly as before. Pause and Stop are executing at the same time. I really don't get what's happening as the actual code makes sense.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 04:20:52 am
content: There are too many pieces of your project missing for me to help much.Questions:Do theRx_Datavalues correspond to one of four switches: START/RESUME, SPEED-UP, SPEED-DOWN, and STOP/PAUSE?What is thestart_statusvariable for? start_status : 0==stopped, 1==runningWhat is theresumevariable for?

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 04:48:16 am
content: If I understand correctly.....Code:void check_speed_command(){// start_status = 0==Stopped, 1==Paused, 2==Runningswitch (Rx_Data) {case 0x32: //SPEED UPif (start_status==2) { //Running?last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC+5;real_dutyCycle = 8*command_dutyC;}Rx_Data=0;break;case 0x31: //SPEED DOWNif (start_status==2) { //Running?last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = command_dutyC-5;real_dutyCycle = 8*command_dutyC;}Rx_Data=0;break;case 0x33: //START and RESUMEif (start_status==0) { //Stopped?HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);HAL_Delay(100);command_dutyC = 5;real_dutyCycle = 8*command_dutyC;start_status=2; //Running}else if (start_status==1) { //Paused?command_dutyC = last_command_D;real_dutyCycle = 8*command_dutyC;start_status=2; //Running}Rx_Data=0;break;case 0x36: //PAUSE and STOPif (start_status==2) { //Running?last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;start_status=1; //Paused}else if (start_status==1) { //Paused?last_dutyC= real_dutyCycle;last_command_D = command_dutyC;command_dutyC = 0;real_dutyCycle = 8*command_dutyC;start_status=0; //Stopped}Rx_Data=0;break;}}

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 04:59:26 am
content: Quote from: MarkF on October 25, 2018, 04:48:16 amYou understand correctly. I'll try this one now.

author: bsfeechannel
author_rank: Super Contributor
timestamp: October 25, 2018, 05:07:28 am
content: Do you initialize the variableresumewhen you declare it? If so, with what value?

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 05:11:48 am
content: Quote from: bsfeechannel on October 25, 2018, 05:07:28 amAll my variables are initialized in zero.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 05:31:02 am
content: Pause/Stop button is physically different from the others. I believe it is extremely noisy, and probably is bouncing too much causing this erroneus behavior. To give more details about the project, Rx_Data is just receiving serial data via UART. Another controller is reading the buttons and send the correspondent value. Maybe the debounce is not still good for this button. It's just a guess.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 06:03:20 am
content: If you are not doing any handshaking with the controller reading the buttons, it may not be a bouncing problem. It could be as simple as holding the button down too long and this code thinking it was pressed again.Ideally, you would want the other controller to wait until it sees that Rx_Data has been set to zero before setting a new value.There might be a way to trick the check_speed_command() function by forcing a delay for say 1 sec before reading Rx_Data again. You could try this to see if it's your logic or if it's a bouncing or holding the button too long issue. Make the delay even a few seconds to test it.Something like:Code:void main(){int block=0;if (block==0) {check_speed_command();block=10;}else if (block>0) {Rx_Data=0;block--;delay(100); //Wait 100ms}}But, you really need some kind of bi-directional communication between the two controllers.

author: XaviPacheco
author_rank: Regular Contributor
timestamp: October 25, 2018, 06:13:04 am
content: I tried the delay. Sometimes it works, sometimes not. Have to confess this is one of the weirdest problems I've ever seen.

author: MarkF
author_rank: Super Contributor
timestamp: October 25, 2018, 06:26:03 am
content: When reading switches, I don't actually process them until the switch is released. That solves the bounce and holding the switch issue. It's very hard to press a switch fast enough not to see it more than once.Here is what I do:Code:void read_switches(){int SW0;int lastSW0=0;int SW1;int lastSW1=0;int SW2;int lastSW2=0;int SW3;int lastSW3=0;SW0 = GetSwitchValue(0);if (lastSW0==1 && SW0==0) Rx_Data=0x33; // If button released, send START valuelastSW0 = SW0;SW1 = GetSwitchValue(1);if (lastSW1==1 && SW1==0) Rx_Data=0x36; // If button released, send STOP valuelastSW1 = SW1;SW2 = GetSwitchValue(2);if (lastSW2==1 && SW2==0) Rx_Data=0x32; // If button released, send SPEED-UP valuelastSW0 = SW0;SW3 = GetSwitchValue(3);if (lastSW3==1 && SW3==0) Rx_Data=0x31; // If button released, send SPEED-DOWN valuelastSW3 = SW3;if (Rx_Data != 0) {send_rx_data();Rx_Data=0;}