目录
串口是什么
串行接口(Serial Interface)是指数据一位一位地顺序传送,其特点是通信线路简单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成本,特别适用于远距离通信,但传送速度较慢。一条信息的各位数据被逐位按顺序传送的通讯方式称为串行通讯。串行通讯的特点是:数据位的传送,按位顺序进行,最少只需一根传输线即可完成;成本低但传送速度慢。串行通讯的距离可以从几米到几千米;根据信息的传送方向,串行通讯可以进一步分为单工、半双工和全双工三种
串口作用
写程序是为了能够达到想要的作用,但是仅仅通过程序来不是很方便,这时,我们就开始考虑通过串口去控制着我们的程序,从而实时达到想要的结果。由此可知,串口可以帮助我们控制程序,也就是通过串口实现了电脑控制程序,不仅如此我们还可以使用蓝牙、WIFI等等去控制程序;
串口控制LED灯
串口控制芯片
串口工作流程
依照下面的流程图可知,大致模块可以分为
1——引脚
2——数据寄存器
3——控制器
4——波特率
串口实现框图(源于:STM32野火)
串口常用寄存
USART_SR | 状态寄存器 |
CTS | CTS标志 |
TXE | 发送数据寄存器空 |
TC | 发送完成 |
RXNE | 度数据寄存器非空 |
PE | 检验错误 |
USART_SR
USART_BRR | 波特率寄存器 |
DIV_Mantissa | 整数部分 |
DIV_Fraction | 小数部分 |
USART_BRR
USART_CR1 | 控制寄存器1 |
UE | USART使能(串口大门) |
M | 字长 |
WAKE | 唤醒 |
PCE | 校验使能 |
PS | 检验选择方式 |
PEIE | PE中断使能 |
TXEIE | 发送中中断使能 |
TCIE | 发送完成中断使能 |
RXNIE | 接收空中断使能 |
TE | 发送使能 |
RE | 接收使能 |
RWU | 接收唤醒 |
USART_CR1
UASRT_CR2 | 控制寄存器2 |
STOP | 停止位 |
CLKEN | 时钟使能 |
CPOL | 时钟极性 |
CPHA | 时钟相位 |
USART_CR2
USART_CR3 | 控制寄存器3 |
CTSIE | CTS中断使能 |
CTSE | CTS使能 |
RTSE | RST使能 |
IRLP | 红外低功耗 |
IREN | 红外模式使能 |
USART_CR3
TX:数据发送 TC:发送完成(多字节)
RX:数据接收 TXIE:发送完成中断使能
SCLK:时钟(仅同步通信使用) RE: 接收使能
nRTS:请求发送(Request To Send) RXNE:读数据寄存器非空
nCTS:允许发送(Clear To Send) RXNEIE:接收完成中断使能
TE:发送使能 TXE:发送数据寄存器为空(单字节)
串口初始化
串口要想使用,首先得打开GOIP的时钟,在打开USART的时钟,这样才使二者正常的结合运作;
打开各个时钟——TX发送数据管脚配置——RX接收数据管脚配置——USART串口配置——(串口中断优先级)——打开接收中断使能——串口使能
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
//GPIO的时钟开启
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
//串口时钟打开
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK,ENABLE);
//TX配置
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT,&GPIO_InitStruct);
//RX配置
GPIO_InitStruct.GPIO_Pin=DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT,&GPIO_InitStruct);
//USART配置
USART_InitStruct.USART_BaudRate=DEBUG_USART_BAUDRATE;
USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_InitStruct.USART_Parity=USART_Parity_No;
USART_InitStruct.USART_StopBits=USART_StopBits_1;
USART_InitStruct.USART_WordLength=USART_WordLength_8b;
USART_Init(DEBUG_USARTx,&USART_InitStruct);
//串口中断优先级设置
NVIC_Configuration();
//接收中断使能
USART_ITConfig(DEBUG_USARTx,USART_IT_RXNE, ENABLE);
//串口使能
USART_Cmd(DEBUG_USARTx,ENABLE);
}
串口发送过程
数据发送的主要就是在 引脚 和 数据寄存器 里面流转;
首先数据是通过
1、GPIO管脚传入PWDATA
2、发送数据寄存器(TDR)
3、 发送移位寄存器
4、IrDASIR解码
5、TX管脚
发送数据的路径是这样的,但是想要达到这样的路径,我们还需要先配置
打开串口的大门 UE=1
打开串口的小门 TE=1
中途涉及到一些USART_SR状态寄存器的改变
TXE TC
我们后面的发送需要用到这几个状态位去检测是否发送完成;
发送数据代码
这里分为好几种类别,比如:发送一个字节,发送两个字节,发送数组,发送字符串
//发送一个字节
void USART_SendByte(USART_TypeDef* Usartx,uint8_t Data)
{
USART_SendData(Usartx,Data);
while(USART_GetFlagStatus(Usartx,USART_FLAG_TXE)==RESET);
}
//发送两个字节
void USART_SendHalfWord(USART_TypeDef* Usartx,uint16_t Data)
{
uint8_t Temp_H,Temp_L;
Temp_H=(Data&0xFF00)>>8;
Temp_L=Data&0xFF;
USART_SendByte(Usartx,Temp_H);
USART_SendByte(Usartx,Temp_L);
}
//发送数组
void USART_SendArray(USART_TypeDef * Usartx,uint8_t Array[],uint8_t num)
{
uint8_t i;
for(i=0;i<num;i++)
{
USART_SendByte(Usartx,Array[i]);
}
while(USART_GetFlagStatus(Usartx,USART_FLAG_TC)==RESET);
}
//发送字符串
void USART_SendStr(USART_TypeDef * Usartx,uint8_t *Str)
{
// uint8_t i=0;
do
{
USART_SendByte(Usartx,*(Str++));
}while(*(Str-1)!='\0');
while(USART_GetFlagStatus(Usartx,USART_FLAG_TC)==RESET);
}
串口接收过程
1、RX
2、IrDASIR解码
3、接收位移寄存器
4、接收数据寄存器
5、PRDATA
接收数据的路径是这样的,但是想要达到这样的路径,我们还需要先配置
打开串口的大门 UE=1
打开串口的小门 RE=1
中途涉及到一些USART_SR状态寄存器的改变
RXNE
后面的接收需要用到这几个状态位去检测是否发送完成;
串口接收代码
接收代码简单,同时为了更加清晰,我们在这个中断还加入了反馈信息,能够清晰的知道数据被串口收到;
串口接收数据为什么要中断呢?
电脑发送数据是一个字节接着一个字节,两个字节之间会有延时,所以收到数据你需要尽快处理,不然可能会被新的数据覆盖,配置中断就是为了及时响应把数据读出存储起来。所以串口内收到数据后状态位就会置1,在中断里把数据存储 然后及时把状态位清零接收下一字节数据。
//这里是放在了中断函数里面接收数据,只要串口已有数据过来就立马进入中断,
//从中获取数据,为了防止误判断,在中断里面再次判断是否接数据
void DEBUG_USART_IRQHandler()
{
uint8_t temp;
if(USART_GetFlagStatus(DEBUG_USARTx,USART_FLAG_RXNE)!=RESET)
{
temp=USART_ReceiveData(DEBUG_USARTx);
USART_SendData(DEBUG_USARTx,temp);//反馈信息
}
}
当然了,这样接收数据需要配置的东西有点多,所以可以使用getchar()函数,前提是对它进行重定向;
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
/* 有了这个等待就不需要在中断中进行了 */
while( USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE)==RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
——参考于STM32野火