零死角玩转stm32中级篇1 您所在的位置:网站首页 i2c最长距离 零死角玩转stm32中级篇1

零死角玩转stm32中级篇1

2023-03-23 14:17| 来源: 网络整理| 查看: 265

本篇博文目录: 一.通信相关概念1.通信的三种分类(1) 串行通信和并行通信(2) 同步传输和异步传输(3) 半双工,全双工,单工 2.常见的通信方式及其分类 二.串口通信相关概念1.串口通信2.串口通信的几个比较重要的参数3.串口的硬件接线(1) DB9和DB25(2) 交叉线和直通线(3) USB转串口 4.串口工作过程分析(1) 波特率控制(2) 收发控制(3) 数据存储转移部分 三.使用串口通信进行发送,接收

一.通信相关概念 1.通信的三种分类

通信按数据传输方式进行分类,可以分为串行通信和并行通信;按通信机制方式进行分类,可以分为同步传输和异步传输。按照数据传输方向和能力进行分类,可以分为单工,半双工和全双工。

(1) 串行通信和并行通信

串行通信:数据是按照单个比特一个接一个地传输的,需要在数据位之间插入控制位,以确保数据的传输正确。串行通信的优点是使用较少的导线,在长距离传输时更稳定,但传输速度相对较慢。

在这里插入图片描述

并行通信:数据是同时传输多个比特,需要更多的导线来实现。并行通信的优点是传输速度快,但成本高且容易产生电源噪声等干扰。

在这里插入图片描述

备注:图片来源于https://www.eefocus.com/e/526547.html

(2) 同步传输和异步传输

同步通信:发送方和接收方使用共同的时钟信号进行数据传输和控制,这种方式的数据传输速度较快,但需要在发送和接收端维护相同的时钟,并且相对复杂。

在这里插入图片描述

异步通信:在数据传输过程中不需要任何时钟同步信号,而是在数据之间通过特定的协议进行数据同步。这使得异步通信更加简单易用,但传输速率相对较慢,数据传输可靠性也较差。

在这里插入图片描述

(3) 半双工,全双工,单工

单工(Simplex):单工通信只能在一个方向上进行信息传输,即信息只能从一个方向的发送器传送到另一个方向的接收器,无法进行双向传输。例如,电视广播和无线电广播就是一种单向通信,只能通过广播信号发送信息,而无法接收信息反馈。

在这里插入图片描述

半双工(Half Duplex):半双工通信只能在同一时间内进行单向传输,即信息只能从一个方向的发送器传送到另一个方向的接收器,不能同时进行双向传输。例如,对讲机就是一个典型的半双工通信设备,同一时间内只能有一方进行发言,另一方只能听取,不能同时说话和听取。

在这里插入图片描述

全双工(Full Duplex):全双工通信可以在同一时间内进行双向传输,即信息可以同时从两个方向进行传输,例如电话通信、网络通信等。在全双工通信中,每个通信实体都拥有一个发送器和一个接收器,能够在不影响对方通信的情况下进行同时的双向数据传输。

在这里插入图片描述

备注:图片来源于https://zhuanlan.zhihu.com/p/361655746

2.常见的通信方式及其分类 同步/异步+串行/并行 类型描述通信协议数据传输速率传输距离应用同步串行通信发送方与接收方在时钟方面保持同步,逐位地按照固定的时间间隔同时发送或接收数据SPI、I2C、Microwire等Mbps通常不超过一个设备的长度短距离通信、芯片与芯片之间的通信异步串行通信发送方和接收方不需要保持时钟同步,每个数据字节之间有一个起始位和一个或多个停止位,实现了帧同步UART、RS-232等Kbps通常不超过几十米数据采集、远程控制、较短距离通信同步并行通信发送方和接收方在时钟上保持同步,同时传输多个数据位ISA总线Mbps通常不超过一个设备的长度高速数据传输异步并行通信发送方和接收方不需要时钟同步,在特定情况下可以同时传送多个数据位USB、PCI总线等Gbps通常不超过几米高速数据传输、外部存储设备 其他通信: 类型描述通信协议数据传输速率传输距离应用USB通信通过USB接口连接各种外部设备,支持异步传输、同步传输和流传输等多种工作模式USB 1.x/2.x/3.xGbps通常不超过几米外部设备连接、高速数据传输CAN通信用于工业自动化和汽车电子领域的数据总线标准,支持多个节点之间的数据传输CAN 2.0BMbps数百米至数千米工业自动化、汽车电子Ethernet通信基于帧格式的网络协议,用于互联网和局域网通信,支持快速、可靠的数据传输IEEE 802.3Gbps通常不超过几百米网络通信、数据中心、局域网WiFi通信基于无线局域网技术的通信方式,通过无线网络实现设备之间的数据传输IEEE 802.11Gbps通常不超过几十米移动设备、家庭网络、公共场所Bluetooth通信短距离、低功耗的无线通信技术,主要用于移动设备之间的数据传输Bluetooth 4.0/5.0Mbps通常不超过几十米移动设备、家庭娱乐、智能家居 二.串口通信相关概念 1.串口通信

① 串口通信是指通过串行通信接口来进行数据传输的一种通信方式。串口通信有两种基础协议:同步协议和异步协议,其中异步协议广泛应用于单片机开发中。 ② 在异步协议中,通信双方的时钟并不需要进行同步,而是利用起始位和停止位来判断每一个字节的开始和结束。异步通信中最常用的协议是UART(Universal Asynchronous Receiver-Transmitter),UART只需要使用一根发送线和一根接收线即可完成单向或双向的串口通信。 ③ 串口通信可以实现点对点和多点通信,实现简单,价格低廉,但数据传输速率较慢,一般采用的通信速率为115200bps以下。在单片机开发中,串口通信被广泛应用于与电脑之间的数据传输、与传感器之间的数据传输以及与其他单片机之间的数据传输等场景。

在这里插入图片描述

2.串口通信的几个比较重要的参数

串口通信的几个比较重要的参数包括:

波特率(Baud Rate):表示通信双方之间每秒传输的比特数,通常用bps(bits per second)来表示。波特率越高,数据传输速度越快,但同时也会增加误码率,降低传输可靠性。

数据位(Data Bits):表示每个字节中所包含的数据位数,常见的取值有5、6、7和8位。数据位的选择取决于数据所包含的信息量以及传输的精度要求。

停止位(Stop Bits):表示每个字节传输结束后,发送方在发送线上保持的电平状态,通常有1位和2位两种取值。停止位的作用是为了告诉接收方当前数据传输已经结束。

校验位(Parity):在数据传输过程中,加入一个校验位来判断数据是否正确传输。常见的校验方式有奇偶校验、偶校验、无校验等,其中奇偶校验最为常用。

以上参数需要双方进行协商确定,并在通信时保持一致,否则数据传输将会出现错误。在单片机开发中,常常使用的串口通信参数为波特率9600bps、8数据位、1停止位、无校验位。

3.串口的硬件接线 (1) DB9和DB25

串口线的接口标准通常有DB9和DB25两种,其中DB9有9根引脚,适用于较少信号的串口设备,而DB25有25根引脚,适用于需要传输大量信号的串口设备。在串口线的选择时,需要根据具体的设备类型和接口标准进行选择。同时,还需要注意串口线的长度和屏蔽效果,以确保数据传输的稳定性和可靠性。

DB9

DB9是一种常用的串口接口标准,也称作DE-9(D形9针),其中“D”指代连接器的外形类似于字母D。DB9接口共有9个引脚,分别为:

DCD(Data Carrier Detect) - 数据载波检测RD(Data Receive) - 数据接收TD(Data Transmit) - 数据发送DTR(Data Terminal Ready) - 数据终端就绪GND(Signal Ground) - 路径接地DSR(Data Set Ready) - 数据集就绪RTS(Request To Send) - 请求发送CTS(Clear To Send) - 清除发送RI(Ring Indicator) - 响铃指示

DB9接口广泛应用于串口设备之间的通信,如串口打印机、调制解调器、路由器、终端设备等。在使用DB9接口时,需要注意接口针脚的正确连接和通信参数的正确设置,以确保数据传输的稳定和可靠。

在这里插入图片描述

DB25

DB25是一种串口接口标准,也称作DE-25(D形25针),其中“D”指代连接器的外形类似于字母D。DB25接口共有25个引脚,与DB9接口相比,其拥有更多的信号引脚,能够支持更复杂的通信方式。DB25接口的引脚定义如下:

1.protective ground(保护接地) 2.TxD(Data Transmit) - 数据发送 3.RxD(Data Receive) - 数据接收 4.RTS(Request To Send) - 请求发送 5.CTS(Clear To Send) - 清除发送 6.DSR(Data Set Ready) - 数据集就绪 7.Signal ground(Signal Ground) - 信号地 8.CD(Carrier Detect) - 载波检测 9.RI(Ring Indicator) - 响铃指示 10.交替行选通 11.设备选择1 12.设备选择2 13.设备选择3 14.设备选择4 15.线路就绪 16.时钟 17.端口就绪 18.暂停 19.申请握手 20.结束握手 21.数据线就绪1 22.数据线就绪2 23.数据线就绪3 24.数据线就绪4 25.保留

DB25接口广泛应用于串口设备之间的通信,如计算机、打印机、调制解调器、路由器、终端设备等。在使用DB25接口时,需要注意接口针脚的正确连接和通信参数的正确设置,以确保数据传输的稳定和可靠。

在这里插入图片描述

(2) 交叉线和直通线

串口的连接需要结合实际原理图来连接,看是采用的交叉线方式还是直通线方式,如果采用交叉线方式就把单片机的TXD与其他设备的RXD相连,RXD与TXD相连;如果采用的是直通线就把单片机的TXD与其他设备的TXD相连,RXD与RXD相连。

交叉线

标准串口引脚2是RX,引脚3是TX,(即九针串口的2号引脚连接的是主控芯片的RXD引脚,3号引脚连接的是主控芯片的TXD引脚),如果单片机开发板的串口和电脑串口都是标准串口,则俩串口应该用交叉线连接。(单片机的TXD连接电脑的RXD;单片机的RXD连接串口的RXD)

直通线

不过现实中直通线居多,为了配合直通线的使用,在画板的时候,把主控芯片的RXD引脚连接至串口的3脚(RXD实际是TXD),主控芯片的TXD引脚连接至串口的2脚(TXD实际是RXD),这样这个开发板上的串口就不是标准串口了,即2变成TX,3变成RX,和标准串口连接时当然应该使用直连线了。(单片机的TXD(实际是RXD)和电脑的TXD相连;单片机的RXD(实际是TXD)和电脑RXD相连)

在这里插入图片描述 备注:参考了这篇博文:https://new.qq.com/rain/a/20210527A01UNY00

(3) USB转串口

① USB转串口是指通过USB接口将计算机与串口设备进行连接的一种方式。由于现代笔记本电脑大多已经取消了串口接口,而很多应用场合仍需要使用串口设备进行通信,因此USB转串口逐渐成为了一种常见的解决方案。 ② USB转串口一般需要使用专门的转换器,这种转换器内部会集成一个串口芯片和USB芯片,可以实现USB和串口之间的信号转换和协议转换。在使用时,用户只需要将USB转串口转换器插入计算机的USB接口上,就可以通过串口通信软件来访问串口设备进行数据传输。 ③ 需要注意的是,不同的USB转串口转换器支持的串口标准可能不同,如RS232、TTL等,因此在选择转换器时需要确认其支持的串口标准是否符合自己的需求。同时,在使用USB转串口转换器时也需要特别注意其驱动程序是否已经安装,以及通信参数的设置是否正确。

在这里插入图片描述

4.串口工作过程分析

串口外设的架构图从下至上,我们看到串口外设主要由三个部分组成,分别是 波特率的控制部分、收发控制部分及数据存储转移部分 。

在这里插入图片描述

(1) 波特率控制

波特率,即每秒传输的二进制位数,用 b/s (bps)表示,通过对时钟的控制可以改变波特率。在配置波特率时,我们向 波特比率寄存器 USART_BRR 写入参数,修改了串口时钟的 分频值 USARTDIV 。 USART_BRR 寄存器 包括两部分,分别是 DIV_Mantissa (USARTDIV 的整数部分)和 DIVFraction (USARTDIV的小数)部分,最终,计算公式为USARTDIV=DIV_Mantissa+(DIVFraction/16)。USARTDIV 是对串口外设的时钟源进行分频的,对于 USART1 ,由于它是挂载在 APB2 总线上的,所以它的时钟源为 f PCLK2 ;而 USART2、3 挂载在APB1 上,时钟源则为 f PCLK1 ,串口的时钟源经过 USARTDIV 分频后分别输出作为 发送器时钟 及 接收器时钟 ,控制发送和接收的时序。

(2) 收发控制

围绕着发送器和接收器控制部分,有好多个寄存器:CR1、CR2、CR3、SR,即 USART 的三个 控制寄存器 (Control Register)及一个 状态寄存器 (StatusRegister)。通过向寄存器写入各种 控制参数 ,来控制发送和接收,如奇偶校验位,停止位等,还包括对 USART 中断的控制;串口的 状态 在任何时候都可以从状态寄存器中查询得到。

(3) 数据存储转移部分

收发控制器根据我们的寄存器配置,对 数据存储转移部分 的 移位寄存器 进行控制。当我们需要发送数据时,内核或 DMA 外设(一种数据传输方式)把数据从内存(变量)写入到 发送数据寄存器 TDR 后, 发送控制器 将适时地自动把数据从 TDR 加载到 发送移位寄存器 ,然后通过 串口线 Tx ,把数据 一位一位 地发送出去,在数据从 TDR 转移到 移位寄存器 时,会产生 发送寄存器TDR 已空事件 TXE ,当数据从 移位寄存器 全部发送出去时,会产生数据 发送完成事件 TC ,这些事件可以在 状态寄存器 中查询到。而 接收数据 则是一个 逆过程 ,数据从 串口线 Rx 一位一位地输入到 接收移位寄存器 ,然后自动地转移到 接收数据寄存器 RDR ,最后用内核指令或 DMA读取到内存(变量)中。

三.使用串口通信进行发送,接收 usart1.c #include "usart1.h" #include #if USART1_RX_EN uint8_t USART1_RX_Buffer[USART1_RX_MAX] = {0};// 接收缓存 uint8_t USART1_RX_Index = 0; // 接收下标 uint8_t USART1_RX_OverFlag = 0;// 接收完成 #endif // 初始化中断优先级 static void NVIC_Configuration(void){ NVIC_InitTypeDef NVIC_InitStructure;// 中断控制器 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 配置优先分组 // 中断源 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 抢占优先级 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 子优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 使能中断 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 初始化NVIC NVIC_Init(&NVIC_InitStructure); } // 初始化串口 void USART1_Config(){ // 初始化GPIO_InitTypeDef和USART_InitTypeDef结构体对象 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 开启USART1和GPIOA的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); // 初始化GPIO9(PA9作为TXD) GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;// 复用推挽输出模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;// 初始化的引脚PA9 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 设置GPIO的速率为50MHz GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化GPIO // 初始化GPIO10(PA10作为RXD) GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//初始化的引脚PA10 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;// 浮空输入模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 设置GPIO的速率为50MHz GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化GPIO // 初始化USART1 USART_InitStructure.USART_BaudRate = 115200;// 波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 数据位 USART_InitStructure.USART_StopBits = USART_StopBits_1;// 停止位 USART_InitStructure.USART_Parity = USART_Parity_No ;// 奇偶校验位0 // 无硬件流模式:在无硬件流控制模式下,数据通信没有任何限制,也就是说,当接收缓冲区溢出时会发生数据丢失 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 指定硬件流模式为无硬件流模式 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 工作模式:同时启用串口的发送和接收模式 USART_Init(USART1, &USART_InitStructure);// 初始化串口 USART_Cmd(USART1, ENABLE);// 串口使能 #if USART1_RX_EN // 使能串口接收中断 USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);// 接收数据不为空的中断 // 串口中断优先级 NVIC_Configuration(); #endif } /***************** 发送一个字节 **********************/ void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch) { /* 发送一个字节数据到USART */ USART_SendData(pUSARTx,ch); /* 等待发送数据寄存器为空 */ while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); } /****************** 发送8位的数组 ************************/ void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num) { uint8_t i; for(i=0; i unsigned int k=0; do { Usart_SendByte( pUSARTx, *(str + k) ); k++; } while(*(str + k)!='\0'); /* 等待发送完成 */ while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {} } /***************** 发送一个16位数 **********************/ void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch) { uint8_t temp_h, temp_l; /* 取出高八位 */ temp_h = (ch&0XFF00)>>8; /* 取出低八位 */ temp_l = ch&0XFF; /* 发送高八位 */ USART_SendData(pUSARTx,temp_h); while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); /* 发送低八位 */ USART_SendData(pUSARTx,temp_l); while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); } ///重定向c库函数printf到串口,重定向后可使用printf函数 int fputc(int ch, FILE *f) { /* 发送一个字节数据到串口 */ USART_SendData(USART1, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); return (ch); } ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数 int fgetc(FILE *f) { /* 等待串口输入数据 */ while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(USART1); } usart1.h #ifndef __usart1_h #define __usart1_h #include "stm32f10x.h" #include #define USART1_RX_EN 1 #define USART1_RX_MAX 255 #if USART1_RX_EN extern uint8_t USART1_RX_Buffer[USART1_RX_MAX];// 接收缓存 extern uint8_t USART1_RX_Index; // 接收下标 extern uint8_t USART1_RX_OverFlag;// 接收完成 #endif void USART1_Config(void); void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch); void Usart_SendString( USART_TypeDef * pUSARTx, char *str); void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch); void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num); #endif /*__usart1_h */ stm32f10x_it.c // 串口中断服务函数 void USART1_IRQHandler(void) { uint8_t ucTemp; if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) { ucTemp = USART_ReceiveData(USART1); // 防止下标越界 if(USART1_RX_Index >=USART1_RX_MAX){ USART1_RX_Index = 0; } if(ucTemp != '#'){ USART1_RX_Buffer[USART1_RX_Index++] = ucTemp; } // 发送的结束符 if(ucTemp == '#'){ USART1_RX_Buffer[USART1_RX_Index++] = ucTemp; USART1_RX_OverFlag = 1;// 发送完成 } } USART_ClearITPendingBit(USART1,USART_IT_RXNE); // 清除中断标识【可以加;可不加】 } main.c #include "stm32f10x.h" #include "led.h" #include "usart1.h" #include "string.h" const char cmd1[8] = "on#"; const char cmd2[8] = "off#"; int main(void){ // 初始化串口 USART1_Config(); // 初始化LED ledInit(); ledOnOrOff(LED_ON); while(1){ if(USART1_RX_OverFlag == 1){ // 解析命令 if(strstr((const char*)USART1_RX_Buffer,cmd1)!= NULL){ ledOnOrOff(LED_ON); printf("灯已开"); } if(strstr((const char*)USART1_RX_Buffer,cmd2)!= NULL){ ledOnOrOff(LED_OFF); printf("灯已关"); } // 重置接收标识 USART1_RX_Index = 0; USART1_RX_OverFlag = 0; memset(USART1_RX_Buffer,0,USART1_RX_MAX);// 将缓存请0 } } }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有