全双工就是数据的收和发可以同时进行;半双工就是数据的收和发不能同时进行。
异步时钟是设备双方需要约定对应的波特率;同步时钟是设备双方有一根时钟线,发送或接收数据是根据这根时钟线来的。
单端电平是需要共GND;差分电平不需要共GND,它的数据传输是依靠电压差来传递的。
有些时候设备两端的电压是不同的,所以高低电平的表示电压也是不同的电压表示的。这个时候就需要添加电平转换电路。以上是常见的几种串口电平。485可以传输上千米,而232与TTL可能只能几十米。这些电压都是对地电压。
1000比特就是1s要发送1000位;波特率为9600时,发送一位的时间为1/9600;
固定低电平为起始位,告诉设备我要开始发送了;
固定高电平为停止位,告诉设备我发送好了。(同时把引脚恢复成了高电平)
有3种校验:奇校验,偶校验,无校验。
奇校验就是,包括奇校验在内的9位数据会出现奇数个1;发送数据的时候,若不是奇数,校验位就会补1,若是奇数,校验位就会补0;最后接收数据的时候会检查个数是否正常,是否为奇数。
偶校验就是,包括偶校验在内的9个数据会出现偶数个1;同理。
停止位有三种:1个停止位,0.5个停止位,1.5个停止位
相当于每次发送一个字节的数据,停止位占1个字节或0.5字节或1.5字节。
串口没有发送数据的时候就是空闲高电平。
串口的同步模式一般用于兼容其他的协议,串口一般用异步。
波特率是对时钟比如72MHZ进行分频,然后得到我们想要的波特率,就可以以这样的波特率进行收发数据了。
硬件流控制要多一根线,有点像标志位,判断对面设备是否接收完成我们发送的数据,这根线置高或低电平等。
一旦发送移位寄存器移位完成,TDR寄存器就会把数据往下送,然后置一个标志位。我们就可以判断标志位,要不要写下一个数据等。
打开对应外设与引脚的时钟。配置引脚的模式,发送数据就是引脚输出高低电平,所以选择复用推挽;接收数据,查阅手册可以配置位上拉或者浮空。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //发送数据就是置高低电平,所以选复用推挽,增加输出能力
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //接收数据上拉或者浮空,阅读手册可知道
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate = 9600; //波特率
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制
USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送模式
USART_InitStruct.USART_Parity = USART_Parity_No; //校验无
USART_InitStruct.USART_StopBits = USART_StopBits_1; //停止位长度为1
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //数据帧长度为8
USART_Init(USART1,&USART_InitStruct);
设置波特率为9600,双方的波特率一定要相同哦。
?关闭硬件流控制。
打开发送与接收模式。
无校验。
停止位长度为1。
数据帧的长度为8。
这样我们的串口就配置好了,只差最后一步使能串口USART1
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1,ENABLE);
想要使用串口中断就要先打开通道。
配置中断的通道。
中断函数的名字可以去系统的启动文件中查找。
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0; //定义表示当前状态机状态的静态变量
static uint8_t Rxcount =0;
if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
Serial_RxData = USART_ReceiveData(USART1); //读取数据寄存器,存放在接收的数据变量
if(RxState==0)
{
if(Serial_RxData==0xFF)
{
RxState=1;
Rxcount=0;
}
}
else if(RxState==1)
{
RxData_Packet[Rxcount]=Serial_RxData;
Rxcount++;
if(Rxcount>=4)
{
RxState=2;
}
}
else if(RxState==2)
{
if(Serial_RxData==0xFE)
{
RxState=0;
Serial_RxFlag = 1; //置接收标志位变量为1
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE); //清除USART1的RXNE标志位
//读取数据寄存器会自动清除此标志位
//如果已经读取了数据寄存器,也可以不执行此代码
}
}
在中断函数中完成数据转存,然后在主函数中打印出来
int main(void)
{
OLED_Init();
Serial_Init();
OLED_ShowString(1, 1, "RxData:");
while(1)
{
if(Serial_GetRxFlag()==1) //接收到数据了,判断标志位
{
OLED_ShowHexNum(2,1,RxData_Packet[0],2);
OLED_ShowHexNum(2,4,RxData_Packet[1],2);
OLED_ShowHexNum(2,7,RxData_Packet[2],2);
OLED_ShowHexNum(2,10,RxData_Packet[3],2);
SendPacket(RxData_Packet,4);
}
}
}