作者:马一飞 QQ:791729359
在学习过程中有什么问题可以联系
(原本资料是以网盘的方式公开提供给任何蓝桥杯爱好者进行下载的,但是最近临近蓝桥杯考试,遇到了很多伸手党,我无偿给爱好者们解答学习上的问题,回复得比较慢居然还有同学来说我这样那样,所以决定不再随意提供自己写的源码和资料。博主已经开始参加工作了,也不是闲着没事干盯着电脑手机为你们服务。记住,不要成为伸手党,要自己多动手实现。)
首先我们看下蓝桥杯嵌入式开发板的电路原理图,找到连接串口的引脚。
很明显,我们能够看到他有两个串口,一个是串口1(PA9,PA10),一个是串口2(PA2,PA3),TX为发送端,RX为接收端。不过,我们的蓝桥杯嵌入式开发板并不能直接使用串口1,虽然确实有串口1的电路,但是它连接的确实RS232的9针串口上,也就是说,我们不能直接通过USB去使用到这串口,因此我们一般都用不了这个串口。那么我们一般使用的串口就是串口2了,我们可以直接通过usb下载线去使用这个串口。
接下来我们就看看,如何对这个串口2进行编程。首先我们要先把usart,misc的库函数也添加进来。
这些库函数的c文件所在的目录是:工程目录->Libraries->STM32F10x_StdPeriph_Driver->src 里面。
Stm32f10x_usart.c里面包含了关于串口的库函数,那么我们使用串口就有可能会使用到串口的接收功能,则misc.c里面就包含了中断配置相关的库函数,因此我们需要把它添加进来。
接下来我们就可以来看看代码是怎么编写的。
void USART2_Init(u32 bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//使能串口2时钟
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //开启串口2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级为最高
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级为最高
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//PA2为发送引脚,因此要配置成复用输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);//PA3为接收引脚,因此要配置成浮空输入模式
USART_InitStructure.USART_BaudRate = bound; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能发送接收
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_Init(USART2,&USART_InitStructure); //不使能硬件流控制
USART_Cmd(USART2,ENABLE); //使能串口2
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //使能接收中断
}
第一步:用到串口2,那么就得使能它引脚的时钟,和串口2的时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
第二部:串口的发送我们可以采用查询的方式去发送,但是串口的接收就要使用到串口中断了,因此我们要对串口2进行中断配置。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
这个函数的原型我们可以在misc.c里面找到。
第三部:对串口2相应的引脚进行初始化
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
设置为串口复用模式。
第四部:配置串口2
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
这个函数原型我们可以在stm32f10x_usart.c里面找到。
根据往年蓝桥杯嵌入式赛题的情况来看,一般使用到串口通信的波特率都为9600,不过这并不重要,我们很明显的发现,串口的配置非常简单,甚至比51单片机还要简单,我们可以直接调用stm32的库函数进行配置,根本不需要像51单片机一样需要自己去计算波特率。
第五步:使能串口
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
第六步:使能串口接收中断
void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
这类关于串口配置的函数我们都可以在stm32f10x_usart.h里面找到。
串口配置好了,我们接下来就可以写串口的发送函数。
void USART2_SendString(u8 *str)
{
u8 index = 0;
do
{
USART_SendData(USART2,str[index]); //发送数据
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == 0); //是否发送完成
index++;
}while(str[index] != 0);
}
这个函数的传入参数为一个指针,我们把传入的数据,逐个逐个发送出去,直到发送完毕,void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);可以发送一个字节的数据。同时,要判断这个函数是否发送完成,可以去查看TXE这个标志位。我们可以看看数据手册TXE标志位代表什么。翻到stm32中文参考手册的489页。
可以很清楚的看到,当我们串口还未发送完成的时候,TXE为0,发送完成后TXE为1,那么我们可以判断,加入我们TXE = 0的时候,我们得等待数据发送发成,直到发送完成后我们才进行下一步的操作。
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
是可以获取串口标志位的库函数。
发送掌握了,我们就可以开始撰写串口的接收了。
串口的接收我们得使用到串口中断,首先我们先定义了这么一些变量RXBUF是用来储存串口的接收数据的,RXOVER为接收串口结束标志位,RXCUNT为串口接收计数值,我把串口中断函数放在了stm32f10x_it.c里
void USART2_IRQHandler(void)
{
u8 temp;
if(USART_GetITStatus(USART2,USART_IT_RXNE) == SET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
temp = USART_ReceiveData(USART2);
if(temp == '\n')
{
RXCUNT = 0;
RXOVER = 1;
USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);
}else
{
RXBUF[RXCUNT] = temp;
RXCUNT++;
}
}
}
注意,中断函数的函数名一定不能写错,写错的话,中断是跳不进来了)
在中断函数里面,我们判断RXNE(接收)中断标志位是否被置1,如果接收中断标志位被置1,则代表产生了接收中断,我们就可以开始执行中断里的内容,在执行完中断后,我们要清除RXNE中断标志位,在库函数里我们可以使用USART_ClearITPendingBit函数进行清除
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
然而我们每次中断只会接收到一个字节的数据,假如我们接收到的是一个字符串的话,我们会进行若干次中断,每次中断都把数据手动保存到我们的接收缓冲数组里面。
我们以回车来充当接收结束标志,接收到数据之后,我们先判断是不是’\n’,如果不是我们就把数据保存到RXBUF里面,直到接收到了’\n’就意味着接收数据完毕,我们就可以串口结束标志位RXOVER = 1,串口接收计数值 RXCUNT = 0,同时我们先把串口接收中断失能,直到我们把串口数据处理完毕之后再开启下一次的接收。
那么我们在主函数里面对串口接收数据进行处理
让我们判断到串口接收结束标志位RXOVER为真时,我们才进入到里面进行串口数据的处理,为了更好的演示,我们把接收到的数据发送回上位机,以及把串口的数据显示到LCD里面。当我们把串口的数据处理完毕之后我们把接收缓冲区的数据全部清空,同时使能接收中断准备下一次接收。
把程序下载到开发板中,可以打开串口助手去看看效果
我们发送一个字符串
发现我们串口助手的接收端也收到了相同的字符串,那么我们就可以证明我们这个串口程序是没有问题的。
同时我们的LCD上也显示了相应的字符串。那么我们的串口配置就已经成功了。
在我们蓝桥杯比赛中,赛场提供的串口助手有两个。超级终端并不好用,推荐使用AccessPort,大家在比赛前一定要熟悉好AccessPort串口助手的使用,以免带来不必要的麻烦。
(以上仅属于个人观点)