我是靠谱客的博主 过时铃铛,最近开发中收集的这篇文章主要介绍stm32 程序设计 第一章 USART发送 -阻塞和非阻塞,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

stm32单片机的串口在项目中占据重要的地位,这里指usart/uart。比如向上位机传输当前温湿度传感器的值等,一般采用串口比较简单,程序的调试开发中,串口也使用的多。现在以stm32f405平台为例,介绍串口1的发送代码构成。
1-GPIO的配置:
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA ,ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
GPIO_InitStruct.GPIO_Pin
= GPIO_Pin_9; //T
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Mode
= GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType
= GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; 
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin
= GPIO_Pin_10;//R 
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_Mode
= GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; 
GPIO_Init(GPIOA, &GPIO_InitStruct);
2-串口的配置
USART_InitTypeDef USART_InitStruct;//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//USART1
USART_InitStruct.USART_BaudRate=9600;

USART_InitStruct.USART_WordLength=USART_WordLength_8b;
USART_InitStruct.USART_StopBits=USART_StopBits_1;
USART_InitStruct.USART_Parity=USART_Parity_No;
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;

USART_Init(USART1, &USART_InitStruct);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

USART_ITConfig(USART1,USART_IT_TXE,DISABLE);

USART_ClearITPendingBit(USART1, USART_IT_TXE);

USART_ClearITPendingBit(USART1, USART_IT_RXNE); 
USART_Cmd(USART1,ENABLE);
以上代码大家都很熟悉,这里简单说一下,串口的配置一般注意波特率,IO管脚和是否发送、接收和相应的中断使能,项目中最常见的是中断接收和DMA发送,现在只讲一般的发送,即USART_SendData这种一个字节发送方式,DMA发送后面将会重点介绍。

阻塞式发送:

while(USART1->SR & 0x80)
USART1->DR = m_sendData;
上述代码使用寄存器的方式发送单个字节,就是判断TXE是否置1,然后发送一个字节m_sendData,和USART_GetFlagStatus(USART1,USART_FLAG_TXE)和USART_SendData(USART1,m_sendData)的表示方式一样,一个是寄存器写法,另一个就是库函数写法。其实在项目中,建议外设的配置、初始化等可以用库函数去配置,而中断函数、中途的使能和失能、外设的启动禁止等都可以用简洁的寄存器配置搞定,时间一长就熟悉了而且效率比寄存器高。
什么是阻塞式发送呢,大家看到只要有while(表达式)语句,就是阻塞的标志。如果你要发送的数据很长,而没有采用DMA发送的情况下,程序等待的时间就越长,对其他程序的时序是有严重影响的。例如,你发送256个字节,采用以下方式:
for(i=0;i<256;i++)
{
while(USART1->SR & 0x0080)
USART1->DR = m_sendData[i];
}
上述代码最大的隐患就是卡在while等待这里,整个单片机会在这里等待执行完毕,除了其他的中断函数会优先执行外,这就是常见的阻塞式发送。大型项目一般不用此方法发送数据,当然简单的程序可以采用这样的方式去发送相关信息。下面再来介绍非阻塞发送。

非阻塞发送:

我们知道在发送一个字节前,我们都会去判断发送的状态是否完成,我们会判断TXE是否为1,即移位寄存器是否有新的数据,用while就会等待,我们就用if(表达式)去判断。但是如果if(表达式)不成立呢,怎么发送剩下没有发送的数据呢。我们可以利用队列这样的形式去发送数据,只要if(表达式)成立,那么剩下数据肯定能够发送出去,代码结构如下:
1-定义一个数组,用来存储我们要发送的数据。
u8 i_tx_read = 0 , i_tx_write = 0;
u8 i_cnt =0 ;
char a_send_queue[32];//我们定义一个32字节的长度的队列数组。
2-写一个发送数据的函数,将要发送的字符串等赋值给上述队列数组。函数名字根据个人喜好自己定义。
void send_data_to_queue(char *array , u8 len)
{
for(i_cnt =0 ;i_cnt<len;i_cnt ++)
a_send_queue[i_tx_write++] = array[i_cnt];
}
3-在主程序的while(1)大循环中,增加下面的代码。
if(i_tx_read != i_tx_write)
{
if(USART1->SR& 0x0080)
{
USART1->DR = a_send_queue[i_tx_read++];
}
}
上述代码在大循环中执行,如果此次循环状态不满足执行条件,那么等待下次循环时候再次执行。注意,只要队列中有新的数据,i_tx_read就会去追赶i_tx_write,发送新的字节。
4-变量的范围。
根据数组长度的限制,i_tx_read和i_tx_wrie 不能超过31,因此在他们自++后,增加范围限制。
例如:
i_tx_write++;
i_tx_write &=0x1F;
5-如果数组长度为256 或者 65536 相应的变量i_tx_read 和 i_tx_write 就为u8 和 u16 ,就不需要去限制范围了,因为到达范围后变量自动归零,keil开发环境目前是这样的。
串口的发送就讲到这里了,当然这些都是简单的发送实现方式。后面会介绍中断接收、DMA不定长发送和DMA接收常用实现方法。

最后

以上就是过时铃铛为你收集整理的stm32 程序设计 第一章 USART发送 -阻塞和非阻塞的全部内容,希望文章能够帮你解决stm32 程序设计 第一章 USART发送 -阻塞和非阻塞所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(61)

评论列表共有 0 条评论

立即
投稿
返回
顶部