本文针对串口通讯进行学习
基础知识补充
串行通信: 定义:串行通信是指利用一条传输线将数据一位位地顺序传送。 传输方式:传输一个字节(8个位)的数据时,串口是将8个位排好队,逐个地在1条连接线上传输。 特点:传输速度较慢,抗干扰能力较强,适用于远距离通信,成本较低。
并行通信: 定义:并行通信是指利用多条传输线将一个数据的各位同时传送。 传输方式:传输一个字节(8个位)的数据时,并口是将8个位一字排开,分别在8条连接线上同时传输。 特点:传输速度较高,抗干扰能力较弱,适用于短距离通信,成本较高。
异步: 不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的号位,或者把主体数据进行打包,以数据帧的格式传输数据。
同步: 使用时钟信号进行数据同步,在同步通讯中,数据信号所传输的内容绝大部分就是有效数据,而异步通讯中会包含有帧的各种标识符,所以同步通讯的效率更高,但是同步通讯双方的时钟允许误差较小,而异步通讯双方的时钟允许误差较大。
单工方式: 只允许数据按照一个固定的方向传送,在任何时刻都只能进行一个方向的通信,一个设备固定为发送设备,一个设备固定为接收设备。
优点:可以利用通信信道的整个带宽,所以一次性可以传输更多的数据。 缺点:通信是单向的,设备之间没有相互通信,效率低。例如:广播电台
半双工方式: 两个设备之间可以收发数据,但是不能在同一时刻进行,每次只能有一个设备发送,另一个站接收。
优点:半双工在同一时刻也是占用整条带宽,所以每次也能传输很多数据。 缺点:半双工由于在通信的时候,通信一方在传输数据,另一方只能等待接收数据,存在一点时延。例如:对讲机
全双工 :允许同时在两个方向上进行通信,它将可用通道分为两部分,一部分用于发送数据,另一部分用于接收数据。由于发送和接收数据有单独的路径,因此设备可以在给定时间同时执行这两项任务。 例如:打电话,双方可以同时说话,互不影响
优点:通信双方可以同时发送和接收数据,效率很高。 缺点:假如设备之间不存在专用路径,那么信道容量就会减少一半。
通讯速率:衡量通讯性能的一个非常重要的参数就是通讯速率,通常以比特率来表示。
比特率:表示实际传输的数据速率,即数据每秒钟可以传输的二进制位数。一个比特表示每秒传输一个二进制位。
波特率:是指每秒传输的信号变化的次数,通常用波特表示。一个波特表示每秒传输一个信号变化(通常是电平变化,注意和比特率的区分)。
串口通讯—USART
基于TTL的UART通讯
介绍
TXD发送数据线,RXD接收数据线,GND地线
在USART通信中,接地(GND)是一个非常重要的部分,它确保了信号传输的稳定性和准确性。当两个USART设备接同一个地时,主要起到了以下几个作用:参考电平一致:在电子电路中,接地提供了一个共同的参考电平。当两个USART设备共享同一个接地时,它们的信号电平将相对于这个共同的参考点进行衡量,从而确保信号能够正确地被解释和传输。消除地电位差:如果两个USART设备没有接在同一个地上,它们之间可能存在地电位差(也称为地回路噪声或地噪声)。这种电位差可能导致信号失真或干扰,影响通信质量。通过接同一个地,可以消除或减小这种电位差,提高通信的可靠性。减少电磁干扰:在串行通信中,信号线可能受到外部电磁干扰的影响。接地有助于将这些干扰电流引入大地,减少对信号线的干扰。保护设备安全:接地还可以提供一定程度的设备保护,特别是在遇到雷击或其他电气故障时,有助于防止设备损坏或电击事故的发生。 总之,USART接同一个地主要是为了确保信号传输的稳定性、准确性和安全性。在实际应用中,正确接地是串行通信系统设计的重要部分,需要仔细考虑和实施。
UART桢结构
- 每一位信号的时间长度T(波特率 = 1/T)
如一个波特率为115200的UART波形表示1秒可容纳115200个bit位,也就是说每一位bit数据占大 约8.68us的时长。
- 帧结构中每一项的具体位数
- 是否有校验位,以及校验位的机制(奇/偶/..)
有了这些约定,接收设备只需要等待起始位的到来,再对之后的波形进行固定间隔的采样即可获得传输的具体信息。
编译
- 使能RX 和TX 引脚GPIO 时钟和USART 时钟;
- 初始化GPIO,并将GPIO 复用到USART 上;
- 配置USART 参数;
- 配置中断控制器并使能USART 接收中断;
- 使能USART;
- 在USART 接收中断服务函数实现数据接收和发送。
由于开发板上跳帽线连接PA9--RXD,PA10--TXD,开发板通过串口Type-C链接电脑,双方建立协议可传输数据。
1 typedef struct {
2 uint32_t USART_BaudRate; // 波特率
3 uint16_t USART_WordLength; // 字长
4 uint16_t USART_StopBits; // 停止位
5 uint16_t USART_Parity; // 校验位
6 uint16_t USART_Mode; // USART 模式
7 uint16_t USART_HardwareFlowControl; // 硬件流控制
8 } USART_InitTypeDef;
1) USART_BaudRate:波特率设置。一般设置为2400、9600、19200、115200。标准库函数会根据设定值计算得到USARTDIV 值,并设置USART_BRR 寄存器值。 2) USART_WordLength:数据帧字长,可选8 位或9 位。它设定USART_CR1 寄存器的M 位的值。 如果没有使能奇偶校验控制,一般使用8 数据位;如果使能了奇偶校验则一般设置为9 数据位。 3) USART_StopBits:停止位设置,可选0.5 个、1 个、1.5 个和2 个停止位,它设定USART_CR2 寄存器的STOP[1:0] 位的值,一般我们选择1 个停止位。 4) USART_Parity:奇偶校验控制选择,可选USART_Parity_No(无校验)、USART_Parity_Even(偶校验) 以及USART_Parity_Odd(奇校验),它设定USART_CR1 寄存器的PCE 位和PS 位的值。 5) USART_Mode:USART 模式选择,有USART_Mode_Rx 和USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定USART_CR1 寄存器的RE 位和TE 位。 6) USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有 使 能RTS、 使能CTS、同时使能RTS 和CTS、不使能硬件流。当使用同步模式时需要配置SCLK 引脚输出脉冲的属性,标准库使用一个时钟初始化结构体USART_ClockInitTypeDef 来设置,因此该结构体内容也只有在同步模式才需要设置
usart.c
#include "stm32f4xx.h"
#include "tim.h"//中断
#include "usart.h"//串口
//PA9/10
void USART_Init_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明引脚结构体
USART_InitTypeDef USART_InitStructure; //声明串口结构体
NVIC_InitTypeDef NVIC_InitStructure; //声明NVIC的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //使能RX 和TX 引脚GPIO 时钟和USART 时钟
//初始化GPIO,并将GPIO 复用到USART上;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //端口使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //引脚配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //不考虑功耗,最大功率
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化结构体
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //复用引脚
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //复用引脚
//配置USART 参数;
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //八位数据帧
USART_InitStructure.USART_StopBits = USART_StopBits_1; //一位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //没有校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_Init(USART1,&USART_InitStructure); //串口初始化
//配置中断控制器并使 接收中断;
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; //中断函数
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x1; //响应优先级
NVIC_Init(&NVIC_InitStructure);
//使能USART
USART_Cmd(USART1,ENABLE);
//在USART 接收中断服务函数实现数据接收和发送。
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
}
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch)
{
//发送一个字节数据到USARTx
USART_SendData(USART1,ch);
//监测串口1发送数据寄存器是否为空,为空将跳出
//等待发送数据寄存器为空,TXE 位由硬件置 1,
//它表示:USART_DR (数据寄存器)中可写入下一个数据,而不会覆盖前一个数据。
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
//这里参数str被系统分配四个字节,char型指针接收未命名字符串地址
void Usart_SendString(USART_TypeDef* pUSARTx, char* str)
{
uint16_t k = 0;
do
{
Usart_SendByte(pUSARTx,*(str+k));
k++;
}while(*(str+k)!='\0');
}
//重定向c库函数printf到串口1,这样我们就可以使用printf函数打印输出信息到串口1了
int fputc(int ch, FILE *stream)
{
//发送一个字节数据到串口1
USART_SendData(USART1,(uint16_t)ch);
//等待发送数据寄存器为空
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f4xx.h"
#include <stdio.h>
void USART_Init_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch);
void Usart_SendString(USART_TypeDef* pUSARTx, char* str);
int fputc(int ch, FILE *stream);
#endif
调用printf(已被重定向)可实现发送数据到电脑端。但电脑需要软件处理接收到的数据(我用的是下面这款)
记住,主函数(默认main)中不要只执行一遍就结束了(用while(1)循环保持程序运行)
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //2号分组:2bit给抢占 2bit给响应 0-3 0-3
USART_Init_Config(); //初始化
Usart_SendString(USART1,"5Ta");//方式一
printf("发送的数据为:%d\n",150);//方式二
while(1);
}