通信方式
串/并行通信的概念和特点
-
串行通信:逐位传输,数据位按顺序依次传输,传输速度较慢,成本相对较低,适用于远距离通信、成本敏感的应用场景,如电话线通信、USB接口等。。
-
并行通信:多位同时传输,数据位同时发送和接收,传输速度更快,成本相对较高,适用于短距离、高速率的数据传输场景,如计算机内部总线、计算机内部的CPU与内存之间的数据传输,高速数据传输系统等。
-
抗干扰能力
-
串行通信由于采用单条数据线或差分线传输数据,因此抗干扰能力较强。
-
并行通信由于存在多条传输线,容易受到信号干扰和串扰的影响,因此抗干扰能力相对较弱。
-
通信接口
通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统
(扩展STM32系统,与别的模块互联,实现外挂模块和读取外挂模块数据)
通信协议:制定通信的规则,通信双方按照协议规则进行数据收发
相关概念
全双工:通信双方能够同时进行双向通信,发送线路与接收线路互不影响(两根通信线)(打电话)
半双工:通信双方在同一时间只能进行单向通信(发电报)
单工:数据只能从一个设备到另一个设备,而不能反着来(收音机)
同步:有单独的时钟线(CLK),接收方可以在时钟信号的指引下进行采样
异步:没有始时钟线,需要双方约定一个采样频率,加入帧头帧尾进行采样位置的对齐(在数据库信号中穿插一些同步用的信号位,或者把主体数据进行打包,以数据帧的格式传输数据)
单端:引脚的高低电平都是对GND的电压差,所以必须要接GND
差分:靠两个差分引脚的电压差来传输信号的(使用差分信号可以极大地提高看干扰特性,所以一般差分信号的传输速度和距离都会非常高,性能也不错)
比特率(Bitrate) :每秒传输的比特数量,通常用比特每秒(bps)表示。一个比特表示每秒传输一个二进制位。 波特率(Baudrate):每秒传输的信号变化的次数,通常用波特(baud)表示。一个波特表示每秒传输一个信号变化(通常是电平变化)。
串口通信(使用串行通信)
基于TTL的UART通讯
Universal Asynchronous Receiver/Transmitter
通用*异步收发传输器 是一种串行通信协议 (全双工通信)
TTL电平:+3.3V或+5V表示1,0V表示0
UART是USART协议应用最简单的使用场景。即直接把数字I/O输出的高低电平作为实际的物理信号进行传输。单端需要共地
UART帧结构
波特率:串口通信的速率
空闲位:设备之间不传输数据时以持续的高电平表示空闲
起始位:标志一个数据帧的开始,固定为一个bit的低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行,8bits或9bits
一般地:9位字长选择有校验,8位字长选择无校验,这样每一帧的有效载荷都是1字节
校验位:用于数据验证,根据数据位计算得来
奇校验:1的个数必须为奇数个,不足最后一位补1,足就补0
偶校验:1的个数必须为偶数个,不足最后一位补1,足就补0
停止位:用于数据帧间隔,固定为高电平(1bit(大部分)、1.5bits或者2bits),恢复空闲
空闲状态引脚为高电平1,起始位为低电平产生下降沿
USART串口通讯
Universal Synchronous/Asynchronous Receiver/Transmitter
(通用同步/异步收发传输器)包含UART的所有特性
TX(Transmit)引脚:发送数据 RX(Receive)引脚:接收数据
USART1_TX - PA9,RX - PA10是APB2总线上的,
USART2_TX - PA2,RX - PA3和USART3_TX - PB10,RX - PB11是APB1总线上的
USART初始化结构体——USART_InitTypeDef:
typedef struct {
uint32_t USART_BaudRate; // 波特率
uint16_t USART_WordLength; // 数据帧字长(8 or 9)
uint16_t USART_StopBits; // 停止位
uint16_t USART_Parity; // 校验位
uint16_t USART_Mode; // USART 模式
uint16_t USART_HardwareFlowControl; // 硬件流控制
} 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、不使能硬件流。
串口的发送和接收代码
Ctrl+Alt+空格 联想代码
步骤
1.查看原理图确定串口引脚 USART1 USART1_TX PA9 USART1_RX PA10
2.GPIO配置 ... 选择复用模式 GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF; //复用模式
3.USART1配置 a.结构体申明
USART_InitTypeDef USART_InitStructure;
b.时钟使能 使能USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
c.将GPIO引脚复用为串口 - 使用USTAR1串口
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //TX 发送
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);//RX 接收
d.配置结构体 波特率、模式(收/发)、终止位、校验位、数据位、流控
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验
USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收和发都使能,进行或操作
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件流控
CTS清除发送 RTS请求发送
c.初始化
USART_Init(USART1, &USART_InitStructure);
串口中断(可选) - 接收可以使用查询和中断两种方式 和前面学习的中断一样
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //外部中断4 EXTI4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
重写串口中断服务函数
uint16_t USART_RxData, USART_RxFlag;
uint8_t USART_GetRxFlag(void)
{
if(USART_RxFlag == 1)
{
USART_RxFlag =0;
return 1;
}
return 0;
}
uint8_t USART_GetRxData(void)
{
return USART_RxData;
}
void USART1_IRQHandler(void)
{
//判断串口接收中断标志是否被置位
if(USART_GetITStatus(USART1 ,USART_IT_RXNE) == SET)
{
USART_RxData = USART_ReceiveData(USART1);
USART_RxFlag =1;
//清楚中断标志
USART_ClearITPendingBit(USART1 ,USART_FLAG_RXNE);
}
}
4.使能串口
USART_Cmd(USART1, ENABLE);
5.使用串口
调用USART_SendData / USART_ReceiveData
6.串口重定向
添加stdio.h
//重定向fputc - 是printf的底层
int fputc(int ch, FILE *stream)
{
USART_SendData(USART1 ,(uint16_t)ch);
//等待数据发送寄存器为空
//USART_FLAG_TXE 表示寄存器可以写入下一个数据了,当为SET的时候可以写入
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}
void usart_printf(char *format, ... )//可变参数
{
char String[100];
va_list arg;
va_start(arg,format);
vsprintf(String,format,arg);
va_end(arg);
usart_string(USART1,String);
}
//发单个字符
void usart_sendbyte(USART_TypeDef* usrUSARTx, uint16_t ch)
{
USART_SendData(usrUSARTx,ch);
//等待数据发送寄存器为空
//USART_FLAG_TXE 表示寄存器可以写入下一个数据了,当为SET的时候可以写入
while(USART_GetFlagStatus(usrUSARTx, USART_FLAG_TXE) == RESET);
}
//发字符串
void usart_string(USART_TypeDef* usrUSARTx, char *str)
{
int i= 0;
do
{
usart_sendbyte(usrUSARTx, *(str+i));
i++;
}
while(*(str+i) != '\0' );
}
//发送数组
void usart_sendarray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for(i = 0;i < Length; i++)
{
usart_sendbyte(USART1,Array[i]);
}
}
//返回x的y次方
uint32_t usart_pow(uint32_t x,uint32_t y)
{
uint32_t result = 1;
while(y--)
{
result *= x;
}
return result;
}
//发送数字
void usart_sendnumber(uint32_t number,uint8_t length)
{
uint8_t i;
for(i=0;i<length;i++)
{
usart_sendbyte(USART1, number / usart_pow(10,length - i - 1) % 10 + '0');//从高位开始取 再加给偏移
}
}
main.c
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
OLED_init();
//串口的发送
usart1_init();
usart_sendbyte(USART1,'A');
uint8_t Array[] = {0x42, 0x43, 0x44, 0x45};
usart_sendarray(Array,4);
usart_string(USART1,"HelloWordl!\r\n");// \r\n进行换行
usart_sendnumber(12345, 5);
printf("NUM = %d\r\n",666);
char String[100];
sprintf(String,"NUM = %d\r\n",666);//每个串口都可以使用sprintf进行打印,不涉及重定向的方向
usart_string(USART1,String);
usart_printf("NUM = %d\r\n",666);
//串口的接收 - 查询方式
while(1)
{
if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
{
RxData = USART_ReceiveData(USART1);//读完DR会自动清零标志位
OLED_ShowHexNum(1,1RxData,2);
}
}
}