摘要:异步通信和同步通信异步通信是指通信的发送和接收设备利用各自的时钟来控制数据的发送和接收过程。同步通信在同步通信中,需要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。配置串口,将波特率设置为异步通信的基本参数。
【STM32】标准库与HAL库课程比较研究8 --串行通信详解一、前言二、准备三、通信基本概念1、通信方式2、串行通信与并行通信(1)串行通信(2)并行通信3、异步通信与同步通信(1)异步通信(2)同步通信4、单工、半双工、全双工通信(1)单工通信(2)半双工通信(3)全双工通信(5)通信速率(4)STM 32 f 1的USART介绍, 串行通信介绍(2)USART介绍,USART结构框图(4),USART寄存器的关键控制位(1)TXE(2)TC(3)RXNE 5,STM32与PC主机通信的方法5。 USB转串行模块VI。中断与标准库I中串行端口的通信。配置步骤II。配置项目三。相关方案四。实验效果七。HAL库中与串口的中断通信I. cubemx配置项目II。常见功能说明。主功能程序四。实验效果八。printf IX的重定向。RS232(可选)1的补充说明。接口标准II。逻辑水平的规定。
一、前言本文是对单片机串行通信的详细讲述。串行通信作为STM32单片机的一项重要功能,在程序调试中起着重要的作用。本文从解释通信的基本原理入手,让你一步步了解和使用STM32的串行通信。实验程序包括标准库和HAL库,例程通过串口中断通信实验。你也可以点击目录跳转到你想看的内容。二、准备工作STM32F103开发板(我用的是蒲忠STM32F103ZE开发板)cubemx软件、keil 5(MDK)USB转串口模块(CH340)三、通信的基本概念1 .沟通方法沟通方法可分为多种类型:
根据数据传输方式,可分为串行通信和并行通信。根据通信的数据同步方式,可以分为同异通信和同步通信。按数据传输方向可分为单工、半双工和全双工通信。下面简单介绍一下这些沟通方式。
2.串行通信和并行通信(1)串行通信串行通信是指用一根数据线依次逐位传输数据,每一位数据占用固定长度的时间。
优点:传输线路少,远距离传输成本低。缺点:数据传输控制比并行通信更复杂,速度更慢。(2)并行通信并行通信通常使用多条数据线同时传输数据字节的每一位,通常8位、16位、32位等数据一起传输。
优点:控制简单,传输速度快。缺点:远距离传输成本高,接收机的每一位很难同时接收,抗干扰能力差。3.异步通信和同步通信(1)异步通信异步通信是指通信的发送和接收设备使用各自的时钟来控制数据的发送和接收过程。异步通信以字符(帧)为单位传输,字符之间的间隙(时间间隔)是任意的。
优点:不要求发送端和接收端的时钟严格一致,易于实现。缺点:每个字符加2 ~ 3位做起始位和结束位,帧间有间隙,传输效率不高。
(2)同步通信同步通信时,需要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。有两种方法可以实现这一点:外部同步和自同步。优点:由于传动,传动效率高。缺点:同步困难且成本高。
4.单工、半双工和全双工通信(1)单工通信单工是指数据传输只能是单向的,即一个设备只发送,一个设备只接收。
(2)半双工通信半双工是指数据传输可以双向进行,但需要分时。就是发了就收不到,收了就发不了。
(3)全双工通信全双工是指数据可以同时双向传输。也就是你发了就能收到,收到就发。
5.通信速率衡量通信性能的一个非常重要的参数是通信速率,通常用比特率来表示。比特率是每秒传输的二进制代码的位数,单位是比特每秒(bps)。比如每秒传输200个字符,每个字符格式包含10位(1个起始位,1个停止位,8个数据位),此时的比特率为:10位×200位/秒= 2000 bps。
STM32F1 1的USART介绍。串行通信简介串行通信是指外设与计算机之间通过数据信号线和地线逐位传输数据的一种通信方式,属于串行通信方式。串口是一种接口标准,规定了接口的电气标准,但没有规定接口插线和使用的协议。
2.USART简介USART是一款通用同步异步收发器,可以灵活地与外部设备进行全双工数据交换。UART是一种通用异步收发器,它在USART的基础上削减了同步通信功能。STM32F103ZET6芯片包含3个usart和2个UART外设。
3.USART结构框图
图片在STM32F1xx中文参考手册通用同步异步收发器一章。
结构图重点放在成帧部分,串口收发情况通过寄存器usart _ Sr的TXE、TC、RXNE位了解。
4.USART寄存器的关键控制位(1)txe txe位是USART_SR寄存器的第7位。当它为1时,TDR寄存器中的数据已经传输到移位寄存器;当该位为0时,TDR寄存器中的数据尚未传输到移位寄存器。复位时为1,当TDR寄存器中有数据时立即为0。
(2)TC TC位是USART_SR寄存器的第6位。为1时,发送移位寄存器中的数据;当它为0时,移位寄存器中仍有数据。复位时为1,需要手动清零或读取使其为0。
(3)RXNE接收数据时该位为1,其他时间为0。
5.STM32与PC主机通信的方法串行数据收发线要交叉连接,计算机的TXD要对应单片机的RXD,计算机的RXD要对应单片机的TXD,它们是GND。如下图所示:
动词 (verb的缩写)USB转串口模块USB转串口模块需要和电脑通信,因为电脑上没有RXD和TXD管脚,电脑还需要安装CH340驱动。市面上常见的USB转串口模块:连接电脑,TX连接单片机,TX连接单片机,电源和地连接单片机就可以进行串口通信。我把电脑上的CH340驱动放在网盘上,需要自己下载。Https://pan.baidu.com/s/1bO7mpkwjkB19HXvmD0083Q密码:kpa6
第六,标准库使用串口中断通信。首先,配置步骤(1)启用串行端口时钟和(2)GPIO端口时钟。(2)将串口对应的管脚设置为复用功能。(3)初始化串口参数,包括波特率、字长、奇偶校验等参数。(4)启用串行端口。(5)设置串行端口中断类型并启用。(6)设置串行端口中断优先级并启用串行端口中断通道。
二、配置项目(1)复制上一章的项目,重命名为8。串行端口中断通信。
(2)进入工程文件,进入APP文件,新建一个USART文件夹,存放串口相关的文件。
(3)打开项目,创建一个新文件,命名为usart.h和usart.c..① ②
(4)将文件添加到目录中,并添加头文件的路径。① ②
(5)要使用串口,需要添加相应的文件。① ②
三。相关程序
# include " led . h " # include " delay . h " # include " system . h " # include " usart . h "/* * * * * * * * * * * * * * * * * * * * * *输入:none *返回值:none * * * * * * * * * * * * * * * * * * * * * * * * * */int main(){ sy NVIC _ PriorityGroup config(NVIC _ priority group _ 2);//将抢占式优先级和反应式优先级的LED_Init()分组;usart 1 _ Init(9600);while(1){ }} usart.h
# ifndefusart _ h _ # Define usart _ h _ # include " STM 32 f 10 x . h "/* * * * * * * * * * * *串行引脚* * * * * * * * * */# Define usart 1 _ gpio _ portgpioa # Define usart 1 _ rx _ pingio _ pin _ 10 # Define usart 1 _ tx _ pingio _ pin _ 9/* * * * * * * * * * * *串行函数* * * * * * */void usart 1 _ init(u32 bound);//串口初始化void usart _ send bit(usart _ typedef * usartx,u16 data);//发送单个数据uint 16 _ usart _ receive bit(usart _ typedef * usartx);//接收单个数据void usart _ sendstring(usart _ typedef * usar tx,char * string);//发送字符串#endif usart.c
# include " usart . h "/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *函数名:usart1。* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */void usart 1 _ Init(u32 bound){ GPIO _ Init typedef GPIO _ Init struct;USART _ init typedef USART _ init struct;NVIC _初始化类型定义NVIC _初始化结构;RCC _ APB 2 periphclock cmd(RCC _ APB 2 periph _ gpio a | RCC _ APB 2 periph _ usart 1,使能);//时钟使能gpio _ init struct . gpio _ pin = usart 1 _ tx _ pin;//发送管脚gpio _ initstruct。gpio _ mode = gpio _ mode _ af _ pp//复用推挽输出gpio _ initstruct。gpio _ speed = gpio _ speed _ 50mhz//传输速度gpio _ init (usart1 _ gpio _ port,& gpio _ init struct);//引脚初始化gpio _ init struct . gpio _ pin = usart 1 _ rx _ pin;//接收管脚gpio _ initstruct。gpio _ mode = gpio _ mode _ in _ floating;//浮点输入gpio _ init (usart1 _ gpio _ port,& gpio _ init struct);//引脚初始化usart _ initstruct。usart _ baudrate = bound//波特率usart _ init struct . usart _ hardware flow control = usart _ hardware flow control _ none;//没有硬件数据流控制usart _ initstruct。usart _ mode = usart _ mode _ rx | usart _ mode _ tx;//收发器模式usart _ initstruct。usart _ parity = usart _ parity _ no//没有校验位usart _ initstruct。usart _ stop bits = usart _ stop bits _ 1;//一个停止位usart _ initstruct。usart _ word length = usart _ word length _ 8b;//8位1字节usart _ init (usart1,& usart _ init struct);//初始化串口USART_Cmd(USART1,ENABLE);//串口使能usart _ itconfig (usart1,usart _ it _ rxne,enable);//接收中断使能nvic _ initstruct。nvic _ irqchannel = usart1 _ irqn//要打开的中断通道nvic _ initstruct。nvic _ irqchannelpreeemption优先级= 2;//抢占式优先级nvic _ init struct . nvic _ irqchannelsubpriority = 2;//对应优先级nvic _ init struct . nvic _ irqchannelcmd = enable;//NVIC通道启用NVIC _ Init(& NVIC _ Init struct);USART_ClearFlag(USART1,USART _ FLAG _ TC);//由于//TC位的初始值为1,所以必须先清零}//如果直接用串口发送和接收函数,会出现内容覆盖的问题。所以我们需要重写函数/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *函数名:USART_SendBit* *。* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */void USART _ send bit(USART _ TypeDef * USARTx,u16 Data) {USART_SendData(USARTx,Data);//while(!USART_GetFlagStatus(USARTx,USART _ FLAG _ TXE));//所有等待的数据都转移到移位寄存器//usart _ clearflag (usartx,usart _ flag _ txe);//清除标志位,同时(!USART_GetFlagStatus(USARTx,USART _ FLAG _ TC));//等待所有带usart _ clear标志的数据发出(usartx,usart _ flag _ TC);//清除标志位}/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *函数名:USART_ReceiveBit*。* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */uint 16 _ t USART _ receive bit(USART _ TypeDef * usar tx){ while(!USART_GetFlagStatus(USARTx,USART _ FLAG _ rx ne));//所有等待接收的数据接收usart _ clear标志(usartx,usart _ flag _ rxne);返回USART _ receive data(usar tx);* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *函数名:USART_SendString*函数:串口发送。String:字符指针*返回值:none * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */void ouart _ send。} }/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *函数名称:USART1_IRQHandler* * Function函数。* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */void usart 1 _ IRQ handler(){ u16 r;If (usart _ get it status (usart1,usart _ it _ rx ne)= = set)//判断中断标志{ r = usart _ received data(usart 1);USART_SendBit(USART1,r);}}四、实验效果
七、哈尔库使用串口中断通信。一、cubemx配置项目(1)打开cubemx,新建一个项目,选择自己的芯片。
(2)配置RCC,选择外部高速时钟。
(3)配置时钟树。
(4)配置串口①
模式:设置为异步基本参数:波特率为115200 bits/s,传输数据长度为8 Bit。无奇偶校验,停止位1。接收和发送都被启用(缺省情况下可以)。②打开串口中断。(5)配置项目文件,生成项目。
二、常用函数讲解HAL _ UART _ Transmit();通过串口发送数据,使用超时管理机制HAL _ UART _ Receive();串口接收数据,使用超时管理机制HAL _ UART _ Transmit _ IT();在串行中断模式下发送(只触发一次中断)HAL _ UART _ Receive _ IT();串行中断模式接收(只触发一次中断)HAL _ UART _ Transmit _ DMA();在串行DMA模式下发送HAL _ UART _ Transmit _ DMA();串行DMA模式接收HAL _ UART _ GetState();判断收发是否完成的相关参数:
UART_HandleTypeDef *huart串口的别名如下:我们用的是串口USART1,它的别名是huart1。*要发送的数据pdata Size要发送的字节数超时最大发送时间HAL_UART_STATE_BUSY_RX,接收完成标志HAL_UART_STATE_BUSY_TX,发送完成标志回调函数:
void HAL _ UART _ RxCpltCallback(UART _ handle typedef * huart);//接收中断回调函数Hal _ UART _ txcpltcallback(UART _ handle typedef * Huart);//发送中断回调函数void Hal _ UART _ TXHalfcpltCallback(UART _ handle typedef * Huart);//串口发送半中断回调函数void Hal _ UART _ rxHalfcpltCallback(UART _ handle typedef * Huart);//串口中断接收完成后,串口接收到的回调函数有一半会进入这个函数。该函数为空,需要用户修改。
三、主功能程序
# include " String . h " uint 8 _ t Rx _ String[100];//接收字符串数组uint 8 _ t Rx _ Flag = 0;//接收字符串计数uint8 _ t Rx _ buff//接收缓存
HAL_UART_Receive_IT(&huart1,(uint8_t *)&Rx_buff,1);//打开接收中断
void HAL _ UART _ RxCpltCallback(UART _ handle typedef * huart){ if(huart = = & huart 1){ Rx _ String[Rx _ flag++]= Rx _ buff;//接收字符if(rx _ string[rx _ flag -1]= = 0x0A)//判断接收是否结束{Hal _ UART _ transmit (& Huart1,(uint8 _ t *)&rx _ string,rx _ flag,0x ffff);//字符串发送while(Hal _ UART _ getState(& huart 1)= = Hal _ UART _ State _ Busy _ TX);//判断传输是否完成memset (rx _ string,0x00,sizeof(rx _ buff));//清空接收到的字符串Rx _ Flag = 0;//清除计数器} Hal _ UART _ receive _ it (& huart1,(uint8 _ t *)&rx _ buff,1);//再次打开接收中断}}四、实验效果
八、关于printf重定向C语言中printf函数的默认输出设备是显示器。如果要在串口或LCD上显示,必须在标准库函数中重新定义与输出设备相关的函数。例如,如果使用printf输出到串行端口,则需要将fputc中的输出指向串行端口。这个过程称为重定向。
对于标准库,将这个程序添加到主函数中。
int fputc(int ch,FILE *p) //函数默认在使用printf函数时自动调用{USART_SendData(USART1,(u8)ch);while(USART _ GetFlagStatus(USART 1,USART _ FLAG _ TXE)= = RESET);返回ch;} int fgetc(FILE * p){ uint 8 _ t ch = 0;USART_SendData(USART1,ch);返回ch;}并添加stdio.h头文件,就可以使用C语言中的printf函数,通过串口在电脑上打印字符串。
对于HAL库,将此程序添加到主函数中。
/* * *函数:将C库函数printf重定向到DEBUG_USARTx *输入参数:none *返回值:none *描述:none */int fputc (int ch,file * f){ Hal _ UART _ transmit(& huart 1,(uint8 _ t *)&ch,1,return ch}/* * *函数:将c库函数getchar,scanf重定向到DEBUG_USARTx *输入参数:none *返回值:none *语句:none */int fgetc(FILE * f){ uint 8 _ t ch = 0;HAL_UART_Receive(&huart1,&ch,1,0x ffff);返回ch;}并添加stdio.h头文件,就可以使用C语言中的printf函数,通过串口在电脑上打印字符串。
九。RS232(可选)1的补充说明。接口标准串行通信有很多接口标准,包括RS-232C、RS-232、RS-422A和RS-485。常用的有RS-232和RS-485。RS-232实际上是RS-232C的改进,原理是一样的。这里我们就用RS-232C接口来解释一下。RS-232C是1969年由EIA修订RS-232C标准。RS-232C定义了数据终端设备(DTE)和数据通信设备(DCE)之间的物理接口标准。RS-232C接口要求使用25针连接器,称为DB25。明确规定了连接器的尺寸和每个引脚的排列位置。
2.逻辑电平规则RS-232C也规定了逻辑电平,如下所示:
在TXD和RXD数据线上,逻辑1是(-3)V到(-15)V的电压,逻辑0是3V到15 V的电压..在RTS、CTS、DSR、DTR、DCD等控制线路上,在3V到15V的电压下信号有效(ON状态),在(-3)V到(-15V)的电压下信号无效(OFF状态)。可以看出,RS-232C用正负电压来表示逻辑状态,这与晶体管-晶体管逻辑集成电路(TTL)用高低电平来表示逻辑状态的规定正好相反。
在这里!
评论前必须登录!
注册