<需要知道的串行口相关库函数>
1.初始化函数
void USART_Init(USARTx, USART_InitStruct);
我的嵌入式开发板STM32f107仅有2个支持RS232协议可以实现全双工的异步串行通信的串口,
因此x仅可能为1,2
typedef stuct
{
u32 USART_BaudRate; /*波特率*/
u16 USART_WordLength; /*传送或者接受数据位数,_8b或者_9b*/
u16USART_StopBits; /*传送或者接受停止位数目,_1, _0.5, _2, _1.5*/
u16 USART_Parity; /*奇偶模式,_NO, _Even, _Odd*/
u16 USART_HardwareFlowControl; /*硬件流控制,_None, _RTS, _CTS, _RTS_CTS*/
u16 USART_Mode; /*接收发送使能, _Tx, _Rx*/
u16 USART_Clock; /*USART时钟使能, _Enable, _Disable*/
u16 USART_CPOL; /*SLCK时钟输出特性, _High, _Low*/
u16 USART_CPHA; /*SLCK时钟输出相位, _1Edge, _2Edge*/
u16 USART_LastBit; /*SLCK时钟输出MSB对应时钟, _Disable, _Enable*/
}USART_InitTypeDef;
按照上面结构体初始化串口即可。
2. 使能函数
USART_Cmd(USARTx, FunctionalStateNewState);
NewState: Enable 使能串行口外设
Disable 失能串行口外设
3. 接收数据
u8USART_ReceiveData(USARTx,Data)
检查指定的串行通讯标志位设定与否
FlagStatusUSART_GetFlagStatus(USARTx, USART_FLAG)
<串行初始化>
1. 串口的初始化,然后使能
USART_InitTypeDef USART_IniStructure;
GPIO_InitTypeDefGPIO_InitStructure;
USART_DeInit(USART1);
//设置串口波特率115200
USART_InitStructure.USART_BaudRate = 115200;
//串口一帧接收8位数据
USART_InitStructure.USART_WordLength =USART_WordLength_8b;
//数据帧结尾有1个停止位
USART_InitStructure.USART_StopBits =USART_StopBits_1;
//不采用奇偶校验
USART_InitStructure.USART_Parity= USART_Parity_No;
//不使用硬件流控制
USART_InitStructure.USART_HardwareFlowControl= USART_HardwareFlowControl_None;
//串口1输入输出端都使能
USART_InitStructure.USART_Mode= USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1&USART_InitStructure);
USART_Cmd(USART1 , Enable);
我刚开始以为只要初始化了串口,在使能串口后就可以接受到信息,可试了接近1个小时后PC串口一直没有收到消息,没办法我就只好去百度,原来串口通讯不仅要配置外设模块,对用的GPIO口也要配置,这在以后的各个外设的学习中都要注意(重要),因此RX和TX两个GPIO端初始化程序还需要添加,具体代码如下: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE); //使能相关时钟,复用是必须要使能的
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9; //电路图对应PA9
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_10; //电路图对应PA10
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure);
标准Printf执行retarget处理,调用库函数向串口发送信息
注意:编译前请在工程属性的 "Target“-》”Code Generation“中勾选”Use MicroLIB“,否则没有输出
USART_SendData(USARTx,u8 Data); 发送字节函数
USART_GetFlagStatus(USARTx,USART_FLAG_TC); 发送字节完成标志位
用于判断发送完成,每发送完成一个字节,发送下一字节。
main.c文件头添加#include
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (
option LDLinker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int__io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)
#endif /* __GNUC__ */
文件中添加结构体
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET)
{}
return ch;
}
串口通讯的深入研究
RZ编码和NRZ编码:
RZ编码其中正电平->归零代表1,负电平->归零代表0,因为每位传输后都要归零,所以接受者只要在信号归零采样即可,这样不需要单独的时钟信号,但是在RZ编码中,大部分的数据带宽,都用来传输“归零”而浪费掉了。
NRZ 取消了数据归零的过程,直接读取线路上的信号,因此节省了带宽,但同时也就需要时钟连接以保证能够正确的接受数据。
USART就是采用了NRZ的异步串行通讯方式
波特率:串口每秒发送的bit个数
传输时间的计算(以2k数据b,每帧8位数据,1位停止位,波特率9600,传输完成花费时间)
T = 2*1024/8*(8+1)/9600 = 0.24s
数据位: 计算机每发送一个信息包(帧)的位数,8个字是一字节,Cortex-M3提供的有8位和9位,
这里要注意下如果选用了奇偶校验,那么数据位必须为9位,否则输出的数据会与实际不符。
停止位: 位于单个包的最后一位,典型值有1,2用于提供校正时间同步的机会
奇偶校验位:当使能后在串口通讯数据MSB(最高有效位)中插入经计算的校验位,9位时为数据第9位,用 于检错
硬件流控制:用于数据流控制,通讯的双方由此交换是否停止后继续接收信息,避免因处理数据速度问题而出现的缓存溢出,导致数据的丢失。
CTS:只有CTS输入信号有效(低电平)时才能发送数据。如果在数据传输的过程中,CTS信号 变成无效,那么发完这个数据后,传输就停止下来。如果当CTS为无效时,向数据寄存器里写数据,则要等到CTS有效时才会发送这个数据。
RTS:只有接收缓冲区内有空余的空间时才请求下一个数据。当前数据发送完成后,发送操作就
需要暂停下来。如果可以接收数据了,将RTS输出置为有效(拉至低电平)
串行通讯传输帧的格式(详见STM32中文参考手册25.3.1):
数据帧:8位/9位,包含起始位(低电平),但不包含停止位(高电平),因此数据帧的长度为8/9(数据长度位)+1/2(停止位)
空闲帧:包含停止位,总线持续高电平(发送使能后将发送一个空闲帧)
断开帧:持续低电平,后跟停止位,因此断开帧的长度为不应大于10/11位,串口TE置1时会发送个断开帧。
波特率USART->BRR寄存器的配置(详见STM32中文参考手册25.3.4,用于寄存器控制,需要了解,最好掌握):
可以求出USARTDIV,再根据计算转换为2进制数,即USAER->BRR的值。
以36MHZ,波特率为例9600
则USARTDIV=3.6*10^7/(16*9600) = 234.375
转换为二进制整数部分为)0xEA
小数部分转化为16进制为 0x0.6
则USART->BRR= 0xEA6
<串口输入输出实验>
串口的输入输出实验与上诉并没有什么太大区别,为具体流程如下(以串口1为例):
1.串口复位
USART_DeInit(USART1);
2.使能输入输出口的对应区域的外设时钟以及复用功能时钟,初始化对应GPIO输入输出方式。
输出方式:复用推挽输出,输入方式:浮空输入
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
。。。。。。
GPIO_Init(GPIOx, &GPIO_Instructure);
3.使能串口时钟,初始化串口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
。。。。。。
USART_Init(USART1,&USART_Instructure);
USART_Cmd(USART1 ,ENABLE);
4.串口输出昨天已经学习,输入调用库函数,即可以接收到数值。
const int MaxLength= 20; //缓存区长度
char StoreSting[MaxLength];
只要在接受函数中用do /while()循环,以收到回车(\n)表示接收截至。
大于等于MaxLength仍未收到回车则输出超出申请数组范围,返回
小于MaxLength收到回车则循环结束返回,将数组传送给printf输出。