完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
1.定义 串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。 2.通信基础 1.通讯结构 串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下: 在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。 2.电平标准 根据使用的电平标准不同,串口通讯可分为 RS-232标准 及TTL标准,具体标准如下: 在电子威廉希尔官方网站 中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。 3.数据传输方式: A同步: 传输以数据块为核心,在一个数据块内,字符间无间隔,接受发送同步,有sclk时钟,双方sclk连在一起,提供同步 特点:效率高,无间隔 B异步: 以字符为传输单位,每发一个字符,都得发送一个起始位,(告诉对方我开始发了)结束发送停止位。(我发完了) 特点:效率低,间隔任意 4.串口数据包组成 起始位、数据位(8位或者9位)、奇偶校验位(第9位)、起始停止位(1,15,2位)、波特率设置 5.速率类型: 比特:每秒传输的二进制位 波特:每秒传输的码源个数(串口常用) 注:这俩本质上其实是差不多的 6.通信类型 串行:一个一个传输 如:fsmc 特点:占用资源多,速度慢,看干扰强 并行:多个一起传输 如:spi usart 特点:占用资源少,速度快。抗干扰能力弱,距离近 7.通信方式 单工:数据传输只支持数据在一个方向上传输;如:打印机 半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。如:对讲机,spi 全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端。如:spi,usart 8.概念补充 1.数据包 串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。 2.波特率 由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。 3.起始和停止信号 数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。 4.有效数据 有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。 5.数据校验 在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。 3.USART简介 USART(通用同步异步收发器)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART,它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。 4.串口结构体参数 5.串口相关函数 void USART_Init //初始化函数 (USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); void USART_Cmd //串口使能函数 (USART_TypeDef* USARTx, FunctionalState NewState); void USART_ITConfig //中断配置函数 (USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState); void USART_SendData //串口发送函数 (USART_TypeDef* USARTx, uint16_t Data); uint16_t USART_ReceiveData //串口接收读取函数 (USART_TypeDef* USARTx); FlagStatus USART_GetFlagStatus //获取相应的串口标志位 (USART_TypeDef* USARTx, uint16_t USART_FLAG); ITStatus USART_GetITStatus //中断状态位获取 (USART_TypeDef* USARTx, uint16_t USART_IT); 6.串口配置 1.配置时钟:gpio,串口,引脚复用 2.配置gpioA9,10结构体 3.配置串口结构体 4.初始化,打开串口 5串口发送函数配置 附上参数.c文件代码 #include "stm32f10x.h" #include "usart.h" void usart_init(void) { GPIO_InitTypeDef gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前 USART_InitTypeDef usartinitStucture; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE ); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟 //先配置tx输出引脚io(pa9) gpioinitStructure.GPIO_Pin =GPIO_Pin_9;//选择引脚 gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平 gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//用推挽输出 GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化 //再配置rx输出引脚io(pa10) gpioinitStructure.GPIO_Pin =GPIO_Pin_10; gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平 gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义 //串口结构体的配置 usartinitStucture.USART_BaudRate =115200;//波特率 usartinitStucture.USART_HardwareFlowControl =USART_HardwareFlowControl_None;//无限流 usartinitStucture.USART_Parity =USART_Mode_Rx | USART_Mode_Tx;//输入输出模式 usartinitStucture.USART_WordLength =USART_Parity_No;//无校验位 usartinitStucture.USART_StopBits =USART_StopBits_1;//一个停止位 usartinitStucture.USART_Mode =USART_WordLength_8b;//有效数据长度8bit USART_Init(USART1,&usartinitStucture);//串口1初始化 USART_Cmd(USART1,ENABLE);//打开串口1 7.串口中断配置 1.配置时钟:gpio,串口,引脚复用 2.串口中断组选择 3.配置gpioA9,10,串口结构体与初始化 4.串口与中断控制器联系配置 5.打开串口 6.串口发送函数配置 .c文件 #include "stm32f10x.h" #include "usart.h" void usart_init(void)//串口发送接收和串口中断配置 { GPIO_InitTypeDef gpioinitStructure;//结构体变量定义,结构体定义要在时钟之前 USART_InitTypeDef usartinitStucture; NVIC_InitTypeDef NVICinitStucture; //1.串口中断组的选择 NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2); //2.打开gpio,引脚复用和串口时钟 RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE ); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//配置gpio,串口,串口复用时钟 //3.先配置tx输出引脚io(pa9) gpioinitStructure.GPIO_Pin =GPIO_Pin_9;//选择引脚 gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平 gpioinitStructure.GPIO_Mode =GPIO_Mode_AF_PP;//选择输出方式,用推挽输出 GPIO_Init(GPIOA,&gpioinitStructure );//端口初始化 //4.再配置rx输出引脚io(pa10) gpioinitStructure.GPIO_Pin =GPIO_Pin_10; gpioinitStructure.GPIO_Speed=GPIO_Speed_50MHz;//选择电平大小,初始状态无电平 gpioinitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA,&gpioinitStructure );//再次端口初始化,因为过程相同且都是gpio所以不用再定义 //5.串口结构体的配置 usartinitStucture.USART_BaudRate =115200;//波特率 usartinitStucture.USART_HardwareFlowControl =USART_HardwareFlowControl_None;//无限流 usartinitStucture.USART_Parity =USART_Mode_Rx | USART_Mode_Tx;//输入输出模式 usartinitStucture.USART_WordLength =USART_Parity_No;//无校验位 usartinitStucture.USART_StopBits =USART_StopBits_1;//一个停止位 usartinitStucture.USART_Mode =USART_WordLength_8b;//有效数据长度8bit USART_Init(USART1,&usartinitStucture);//串口1初始化 //6.串口和中断控制器联系配置 USART_ITConfig(USART1, USART_IT_RXNE,ENABLE ); //7.打开串口1 USART_Cmd(USART1,ENABLE); //8.串口中断控制器结构体配置与初始化 NVICinitStucture.NVIC_IRQChannel =USART1_IRQn;//中断通道,选择串口中断 NVICinitStucture.NVIC_IRQChannelPreemptionPriority=1;//配置中断优先级 NVICinitStucture.NVIC_IRQChannelCmd =ENABLE;//使能打开 NVICinitStucture.NVIC_IRQChannelSubPriority =1;//配置中断子优先级 NVIC_Init(&NVICinitStucture);//串口结构体初始化 } void USARTSendByte(USART_TypeDef* USARTx, uint16_t Data)//串口发送字符函数封装 { USART_SendData(USARTx, Data);//串口1发送字符0 while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);//如果数据寄存器空标志位为空,则已经成功发送数据跳出 } void USARTSendstr(USART_TypeDef* USARTx,char*str)//串口发送字符串函数封装 { uint16_t i=0; do { USARTSendByte(USARTx,*(str+i));//串口发送字符函数封装 i++; }while(*(str+i)!=' |