需求: pc端使用串口发送字符串控制开发板led
解决方案: 使用串口接受中断搭配空闲中断来实现。
原理: 串口发送字符串到开发板,开发板触发接受中断,由于串口一次只能发送一个字节,所以会多次进入接受中断,直到接受完所有字符,接受完之后就会触发空闲中断,在空闲中断里判断从接受中断获取到的字符串再进行相应的处理。
坑1:
对于此方案而言,接受中断中不能使用打印函数,因为打印函数会消耗时间,接受中断相当于被打断了一下。然后会被系统认定为空闲,就会出现只接受到一个字符然后就直接进空闲中断的情况。
坑2(也不算坑):
此问题我估计是开发板硬件设计的问题,在主函数的while(1)中一只点亮led4,然后串口中断服务函数中发送控制字符串,发送open就点亮led1,发送close就关闭led1,这时候就会出现有时能打开或者关闭led,有时又不可以。非常奇怪,后面经过多次调试发现,把主函数while(1)中的led4去掉就能完美运行,非常奇怪,我配置所有led初始化对寄存器的操作是完全没有影响到其他led的,最后总结只能是开发板led的供电问题。
核心代码如下:
#include "nvic.h"
u8 str[50] = {0};
void USART1_IRQHandler()
{
static u8 i = 0;
if(USART1->SR & (1<<5)) //判断是否为接收中断
{
str[i] = USART1->DR; //读DR可以清除中断标志位
i++;
}
if(USART1->SR & (1<<4)) //判断是否为空闲中断
{
USART1->SR; //清除中断标志位
USART1->DR;
str[i]='\0'; //字符串需要\0结尾
i = 0; //i重置为了能重复接受
printf("(空闲中断)接收到数据的长度为:%d\r\n",strlen((char *)str));
printf("(空闲中断)开发板接收到的数据为:%s\r\n",str);
if(strcmp("open",(char *)str) == 0)
{
GPIOC->ODR &= ~(1<<5); //点亮led
}
else if(strcmp("close",(char *)str) == 0)
{
GPIOC->ODR |= (1<<5); //关闭led
}
}
}