cancel
Showing results for 
Search instead for 
Did you mean: 

UART 4 bit numeric value communication

soundarya_h_s
Associate III

I am doing the project to control linear motor, For that I am using UART to send start and stop command to start and stop motor, as like this i sending different rpm value from 100 to 3000 randomly to change the ramp of the motor.

The problem that i am facing is for 3 digit number RPM i am getting output, but when is comes to 4 digit value i am not getting proper putput, 
For example:

For 1000 RPM, I am getting 100 RPM as out put

soundarya_h_s_0-1709892543564.png

  • Baud Rate: 115200 bps
  • Data Bits: 8
  • Parity: None
  • Stop Bits: 1

 

void
HAL_UART_RxCpltCallback(UART_HandleTypeDef* huart)
{
  int cmd_ok = 0;
  rxbuffer[strlen(rxbuffer)] = '\0';
  if (strncmp((const char*)rxbuffer, "start", 6) == 0)
  {
    rxbuffer[strlen(rxbuffer)] = '\0';
    flag = 1;
    cmd_ok = 1;
    // MC_StartMotor1();
  }
  else if (strncmp((const char*)rxbuffer, "stop", 5) == 0)
  {
    rxbuffer[strlen(rxbuffer)] = '\0';
    flag = 0;
    cmd_ok = 1;
    // MC_StopMotor1();
  }
  else
  {
    rxbuffer[strlen(rxbuffer)] = '\0';
    char* endptr;
    uint16_t rpmValue = strtol((char*)rxbuffer, &endptr, 10);
    // rpmValue = atoi((char*)rxbuffer);
    if (rxbuffer[0] != '\0' && *endptr == '\0' && rpmValue >= 100 && rpmValue <= 3000)
    {
      MC_ProgramSpeedRampMotor1(rpmValue, 30000);
      // HAL_Delay(60000);
      cmd_ok = 1;
    }
  }

  if (cmd_ok == 1)
  {
    memset(rxbuffer, 0, sizeof(rxbuffer));
    cmd_ok = 0;
    rxindex = 0;
  }
  else
  {
    rxindex++;
  }
  HAL_UART_Receive_IT(&huart2, ((uint8_t*)rxbuffer) + strlen(rxbuffer), 1);
}
18 REPLIES 18

soundarya_h_s_0-1709899464219.png

 

You can put more than one image in a post!

You know that you can set the debugger to display values as characters?

You've shown that "start" is received - but you haven't shown any numbers being received.

Why is your buffer uint16_t ?

Things like strlen are not going to work with that!

 

EDIT

And, again,  What is going on here:

 

 
  rxbuffer[strlen(rxbuffer)] = '\0';

 

strlen is only going to work if the rxbuffer is already NULL-terminated - so this is either pointless, or broken.

 

 
 

soundarya_h_s_0-1709900244384.pngsoundarya_h_s_1-1709900268389.png

In 1st image 850 is received, in second image i sent 1000 it received 100

 

You still haven't addressed the fundamental flaw that your buffer seems to be uint16_t when it should be char.

And what you intend with this:

 

rxbuffer[strlen(rxbuffer)] = '\0';

 

 

In your screenshot, the Docklight is obscuring important detail of the debug output - so we can't see what's going on.

 


@soundarya_h_s wrote:

In 1st image 850 is received, in second image i sent 1000 it received 100


So the receiving is not working.

So you need to look into what's going wrong.

Send one character at a time, and follow-through step-by-step how that gets handled - to see where the handling goes wrong.

With the above-mentioned issues, it's not surprising that things go wrong ...

 

 

TDK
Guru

You're terminating things before the last digit comes in.

> if (rxbuffer[0] != '\0' && *endptr == '\0' && rpmValue >= 100 && rpmValue <= 3000)

Imagine that you've received 3 digits "100". Code gets to this line, it passes (since rpmValue >= 100), so you terminate things and set the speed to 100.

The proper way would be to terminate commands with a "\n" and only act upon those when the terminating character is sent.

 

If you feel a post has answered your question, please click "Accept as Solution".
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	int cmd_ok = 0;
    static int rx_index = 0;
	if (rxbuffer[rx_index] == '\n' )
	{
		if (rx_index > 0 && rxbuffer[rx_index - 1] == '\r')
		{
			rxbuffer[rx_index] = '\0';
			rxbuffer[rx_index - 1] = '\0';
			rx_index = 0;
			int j = 0;
			while (rxbuffer[j] != '\0' && rxbuffer[j] == "stop"[j])
			{
				j++;
			}
			if (j == 4 && rxbuffer[j] == '\0')
			{
				stopflag = 1;
				cmd_ok = 1;
				//MC_StartMotor1();
			}
			else if(j == 2)
			{
				int i = 0;
				while (rxbuffer[i] != '\0' && rxbuffer[i] == "start"[i])
				{
					i++;
				}
				if (i == 5 && rxbuffer[i] == '\0')
				{
					startflag = 1;
					cmd_ok = 1;
					//MC_StopMotor1();
				}
			}
			else
			{
				uint16_t rpmValue = atoi((char*)rxbuffer);
				 for (int i = 0; rxbuffer[i] != '\0'; i++)
				{
					if (!isdigit(rxbuffer[i]))
					{
						rxbuffer[i] = '\0';
						break;
					}
				}
				if (100 <= rpmValue && rpmValue <= 3000)
				{
					 MC_ProgramSpeedRampMotor1(rpmValue,60000);
					 cmd_ok = 1;
				}
				else
				{
					 txflag = 1;
					 cmd_ok =1;
				}
			}
		 }
	 }

Have you tested that code?

You still have problems if rxbuffer is uint16_t; eg,

uint16_t rpmValue = atoi((char*)rxbuffer);

 

How could this possibly work? rx_index is never changed from 0. The logic is better, but you're still not there yet. Yu're close, keep going. Debug, step through code, verify the logic is what you need it to be.

If you feel a post has answered your question, please click "Accept as Solution".

You should use HAL_UARTEx_ReceiveToIdle_DMA since you have variable size strings. Check this git project which explains how it's used. https://github.com/karlyamashita/Nucleo-G431RB_Three_UART/wiki

 

Also you should not be doing any calculations or calls to another function within a interrupt. Save the data and set a flag. Then check the flag in the main loop and then do your calculation or calls.

If you find my answers useful, click the accept button so that way others can see the solution.