目录
一、数据的传送方式
1.串行通信
速度慢,但占用资源少,按顺序传输、逐个位传输,(使用一个数据线就能解决传输问题,即一个I/O口就可以解决问题)
2.并行通信
速度快,但占用资源多,各个位同时传输、多位传输,(多少位数据就需要多少根数据线)
适用于:USART,IIC,SPI
二、数据的通信方式
1、单工通信 iic,spi
A发--单向通道--B收
2、半双工通信 spi
A发--双向通道--B收 / B发--双向通道--A收
(同一时刻时,一个设备发送时,另一个就不能同时进行发送)
3、全双工通信 usart,spi
A发、B发--双向通道--B收、A收
(两个设备在同一时刻都可以进行收发数据,传输)
三、数据的同步方式
【同步 & 异步】
1、同步通信
①数据传送以数据块(多个字符组成的)的形式的;在数据块内,字符与字符间无间隔
②接收与发送时钟严格同步,有同步时钟SCLK
③通信双方的各自的两个时钟SCLK是连在一起的,提供同步时钟;接受与发送是同步的
2、异步通信
①没有时钟线SCLK的约束,因此有了②
②在发送数据之前发送一个起始位, 发送奇偶检验位+想要发送的字符,最后发送停止位
比较 有无时钟SCLK的约束
四、数据的通信速率
1、比特率(在IIC,SPI中使用)Bitrate
每秒传输的二进制位,bit/s
2、波特率(在串口中使用)Baudrate
每秒传输的码元个数
一个二进制位表示一个码元
五、串口通信
TTL电平:数字芯片的电平,单片机使用,0-5V
232电平:电脑串口的电平,工业电平,-3-15V
原生串口通信:直接设备与传感器连接 (eg. GPS模块,WiFi模块...)
1、串口数据包的基本组成
起始位:逻辑0 (第一个低电平)
停止位:逻辑0.5/1/1.5 (高电平) 可以达到校准同步时钟的目的
有效数据位:
校验位:
校验方法有:
奇校验:有效数据+校验位中的“1”个数为奇数; 即如:10010110,有四个1了,校验位加上一个1,凑5个,为奇校验 (九个位传输)
偶校验:有效数据+校验位中的“1”个数为偶数; 即如:10010110,有四个1了,校验位加上一个0,不加1保持4个1不变,为偶校验 (九个位传输)
0校验:校验位总为0
1校验:校验位总为1
无校验:数据不包含校验位
六、串口的结构体
1、串口通信
TX 发送(配置输出模式) RX 接收(配置输入模式,浮空输入)
USART:同步异步收发器
UART :异步收发器
↓ 在“中文参考手册” ↓
可以看出 USART1在APB2总线下,其余在APB1总线下
APB2的频率与AHB系统总线的频率一样 (72*10的6次方 hz )
APB1 (32*10 6)
2、异步收发器的结构体的配置
-
uint32_t USART_BaudRate; //波特率
波特率设置: (在APB2中是)使用固件库时直接设置 =115200 =72 *10(6次方)/16*USATDIV
-
uint16_t USART_WordLength; //配置数据位的字长
有 8位 与 9位
-
uint16_t USART_StopBits; //停止位
正常情况下使用 1 停止位
-
uint16_t USART_Parity; //校验位的配置
-
uint16_t USART_Mode; //模式的设置
USART_Mode_Rx | USART_Mode_Tx 即可 表示Rx输入Tx输出都可行
-
uint16_t USART_HardwareFlowControl; //配置硬件流模式
一般情况下,不做选择
3、同步收发器的结构体配置
uint16_t USART_Clock; //时钟配置
uint16_t USART_CPOL; //极性 配置串口空闲为什么电平
uint16_t USART_CPHA; //相位 配置选择边沿
1Edge 第一边沿 ≈ 上升沿
2Edge 第二边沿 ≈ 下降沿
uint16_t USART_LastBit; //配置最后一位时钟,使能开关
4、常用函数
七、配置串口的发送与接收
- 配置时钟:GPIO口的时钟,串口的时钟,引脚复用的时钟
- 配置GPIO口+串口结构体
- 串口的发送
1、串口接收字符
1、打开APB2下的GPIOA的时钟信号;因为UART1在APB2总线下
2、同时使能引脚复用时钟
3、打开UART1的时钟信号
4、【配置APB2下的GPIOA的结构体】 配置PA9串口---TX线---输出引脚
Mode:推挽输出
5、【配置APB2下的GPIOA的结构体】 配置PA10串口---RX线---输入引脚(接收)
Mode:浮空输入
记得初始化结构体 stm32f10x_gpio.h
6、【配置串口的结构体】
BaudRate=115200;
Mode=USART_Mode_Rx | USART_Mode_Tx;
记得初始化结构体 + 使能串口 USART_Cmd() stm32f10x_uart.h
#include "stm32f10x.h"
#include "usart.h"
void usart_demo(void)
{
GPIO_InitTypeDef GPIOinitStruct;
USART_InitTypeDef USARTinitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
//PA9
GPIOinitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIOinitStruct.GPIO_Pin=GPIO_Pin_9;
GPIOinitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIOinitStruct);
//PA10
GPIOinitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIOinitStruct.GPIO_Pin=GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIOinitStruct);
//串口配置
USARTinitStruct.USART_BaudRate=115200;
USARTinitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USARTinitStruct.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USARTinitStruct.USART_Parity=USART_Parity_No;
USARTinitStruct.USART_StopBits=USART_StopBits_1;
USARTinitStruct.USART_WordLength=USART_WordLength_8b;
USART_Init(USART1, &USARTinitStruct);
USART_Cmd(USART1,ENABLE);
}
2、主函数
int main()
{
USART_SendData(USART1, 'X');//发送字符函数
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//判断串口状态函数
USART_SendData(USART1, 'Y');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
USART_SendData(USART1, '\n');
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
delay(1000);
}
USART_FLAG_TXE 发送空标志位定义;判断当串口的状态是空的时候,即字符发送完毕的时候;执行下一个字符的发送
3、串口接收字符串
在接收字符的基础上,封装2个函数,实现达到字符串输出的目的
封装一个输出单个字符的函数
void USART_SendByte(USART_TypeDef* USARTx, uint16_t data)
{
USART_SendData(USARTx, data);
while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE)==RESET);
}
封装一个输出字符串的函数
void USART_SendStr(USART_TypeDef* USARTx, char *str)//字符串以指针的形成存入
{
uint16_t i=0;
do
{
USART_SendByte(USARTx, *(str + i)); //利用i++逐个通过字符函数进行输出
i++;
}
while(*(str + i) != '\0'); //字符串的最后一个字符是‘\0’,以此为结束标志
while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET); //检查发送完成标志位
}
在使用串口接收字符串时,字符串函数不能直接调用 库里面的输出字符函数USART_SendData ;
否则只会发送字符串的最后一个字符;
所以只能通过封装一个发送字符串的函数,调用USART_SendData,对字符串里面的字符一个一个的进行调用