一、使用阻塞方式收发
阻塞方式,即在程序运行到收发数据时,处理器会等待数据收发完全后再进行下面的操作,在传输数据多和传输数据慢时大大影响了单片机的运行速度,以下介绍阻塞收发的步骤:
首先我们需要定义一个缓冲区,用来存放我们发送的数据:
然后进入收发部分:
可以看到,阻塞收发时接收和发送需要填的参数没有区别,第一位是接收/发送数据的串口位号,第二位是把数据接收到某个指定地方(发送某个地方的数据),这个地方就是我们上面设定的缓冲区,第三位是传输数据的长度,第四位是超时时间的设定,如果在超时时间内没有收发完数据,系统就会跳出传输。
那么代码如下
uint8_t rx_buffer[50];//定义一个缓冲区
memset(rx_buffer,0,sizeof(rx_buffer));//清空缓冲区
HAL_UART_Receive(&huart1,rx_buffer,sizeof(rx_buffer[50]),0xffffffff);//阻塞接收
HAL_UART_Transmit(&huart1,rx_buffer,sizeof(rx_buffer[50]),0xffffffff);//将接收的数据阻塞发送出去
memset(rx_buffer,0,sizeof(rx_buffer));//清空缓冲区,进行下一次收发
上述代码可以发送接收到的数据给用户,下面我将使用串口调试助手验证:
没有问题。
二、使用中断方式收发
相比于阻塞收发,中断收发可以更灵活的收发数据,在未收发时,处理器可以去处理其他指令,在需要收发时触发中断返回去执行收发操作,以下介绍中断收发操作:
中断收发输入参数和阻塞一致,只是后面不用设定超时时间,但要自己编写进入收发中断后的中断回调函数。
在介绍代码之前,先介绍一下printf函数的重定义:
int fputc(int c,FILE *f)
{
uint8_t ch;
ch = c;
HAL_UART_Transmit(&huart1,&ch,1,1000);
return c;
}
在工程中加入上面这段代码,就可以在keil中使用printf函数传输数据,而不用再使用transmit。
定义缓冲区、变量、计数器:
编写主函数:
/* USER CODE BEGIN WHILE */
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET);//这两句用于设定LED亮灭
while (1)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
HAL_Delay(500);//这两句使LED1一直在闪烁,可以验证使用中断发送时不会影响程序其他部分正常进行
memset(rx_buffer,0,sizeof(char)*50);//清空缓冲区
HAL_UART_Receive_IT(&huart1,&rx_data,1);//开始中断接收
/* USER CODE END WHILE */
编写回调函数:
/* USER CODE BEGIN 1 */
char rx_buffer[50];
uint8_t rx_data;
static uint8_t rx_index = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 检验是否是USART1发出的中断
{
if(rx_data == '$') // 检查是否发出数据的最后一位,此处我设置为检验美元符号
{
rx_buffer[rx_index] = '\0'; //将此位(即该字符串最后一位),设为"\0",方便后续用printf打印字符串
printf("Received data: %s\r\n", rx_buffer); // 打印接受的数据
if(strncmp((const char*)rx_buffer, "on",2) == 0) //检验发送的数据是否为“on”
{
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET); // 若是,则打开LED2
}
else if(strncmp((const char*)rx_buffer, "off",3) == 0)//检验发送的数据是否为“off”
{
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET); // 若是,则关闭LED2
}
else
{
printf("ERROR: Invalid command\r\n"); // 如果不是“on”和“off”中的任何一个,则返回错误
}
memset(rx_buffer, 0, sizeof(rx_buffer)); //清空缓冲区,方便下次传输
rx_index = 0; //复位计数器,方便下次传输
}
else
{
rx_buffer[rx_index++] = rx_data; // 将rx_data中的数据一位一位地存放在rx_buffer中
}
HAL_UART_Receive_IT(&huart1, &rx_data, 1); //开始下次传输
}
}
/* USER CODE END 1 */
上面的代码我首先设定了LED1和2,每隔500ms翻转一次LED1的电平,用来验证中断收发时不会影响处理器处理其他指令,效果是LED1一直在闪烁。而LED2由用户输入控制,当用户输入“on$"时,LED2亮;当输入”off$"时,LED2灭,并且会输出用户输入的数据。
下面用串口调试助手测试:
没有问题。