目录
可能对于很多人都不是很了解我们STM32F103系列开发板上的两个USB接口,实际上它们一个是USB SLAVE接口,另一个是USB 串口接口,也就是我们要说的串口。这个串口也就是我们平时烧录程序代码所使用的接口。
对于STM32的串口而言,烧录程序只是其附加功能,串口的作用体现在诸多方面,比如串口调试(我们可以把程序运行的相关信息全部显示到PC机上,从而找到问题所在)。由此可见,作为数据传输通道,它最重要的功能在于通信,也就是我们平时讲的串口通信。
下面小蛋糕将对串口通信展开讲解,其中我们主要分析串行通信。
串口通信简介
串口通信,即串口按位接收和发送字节。串口是一种设备间非常常用的串行通信方式,其简单便捷,大部分电子设备都支持。串口通信可以分为串行通信和并行通信两种。
串行通信分类
串行通信根据不同的划分标准可以获得多个分类:
按照数据传输方向进行分类:
串行通信分类 | 简要说明 |
---|---|
单工通信 | 数据传输只支持在一个方向上传输 |
半双工通信 | 允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输 |
全双工通信 | 允许数据同时在两个方向上传输 |
按照通信方式进行分类:
串行通信分类 | 简要说明 |
---|---|
同步通信 | 带时钟同步信号传输 |
异步通信 | 不带时钟同步信号 |
串行通信过程原理
信号接收通过接收引脚接收后到达接收移位寄存器,接收移位寄存器一位位的接收完数据后,数据保存到接收数据寄存器,这是CPU就可以读取我们接收到的数据,并根据接收到的数据发出相应的命令,这时,我们把CPU产生的命令数据写到发送数据寄存器(TDR),然后数据一位位的发送到发送移位寄存器,再由发送移位寄存器按照事先约定的波特率一位位的移出。
其中,数据发送和接收的波特率分别收发送器控制和接收控制,发送器、接收器分别时钟的控制。具体而言就是:通过设置波特率寄存器,产生了一个值(USARTDIV),然后对产生的时钟除以6,就是我们的波特率。发送器、接收器便按照这个波特率进行数据的发送和接收工作。
实验内容
在这里我们以异步串行通信(UART)作为实例进行分析。
在异步串行通信中,我们实验内容如下:
我们使用串口发送数据,由于数据的发送在开发板上无法体现,所以我们需要设置一个数据发送中断,当数据发送成功后,硬件调用中断服务函数,我们在中断服务函数中编写程序,将我们发送的数据显示出来,然后我们使用我们的串口调试助手进行数据的查看。
代码编写
在本次实验中我们的代码编写主要包括一下三部分:
1、串口初始化函数
2、中断服务函数
3、主函数
下面小蛋糕手把手带你编写串口通信(异步串行通信)代码:
(1)由于我们知道我们需要调用中断,所以我们现在主函数中设置我们的中断优先级分组。
int main()
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
}
(2)然后我们进入串口初始化代码的编写:(这一部分组要包括:串口初始化、GPIO初始化、中断初始化、串口使能),话不多说,上代码:
void MY_USART_init(void)
{
//定义相关初始化参数结构体
GPIO_InitTypeDef GPIOStruct;
USART_InitTypeDef USARTStruct;
NVIC_InitTypeDef NVICStruct;
//使能对应的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//GPIO初始化
GPIOStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIOStruct.GPIO_Pin = GPIO_Pin_9;
GPIOStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIOStruct);
GPIOStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIOStruct.GPIO_Pin = GPIO_Pin_10;
GPIOStruct.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIOStruct);
//中断初始化
NVICStruct.NVIC_IRQChannel = USART1_IRQn;
NVICStruct.NVIC_IRQChannelCmd = ENABLE;
NVICStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVICStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVICStruct);
//串口初始化
USARTStruct.USART_BaudRate = 9600;
USARTStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USARTStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;
USARTStruct.USART_Parity = USART_Parity_No;
USARTStruct.USART_StopBits = USART_StopBits_1;
USARTStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USARTStruct);
//使能指定的串口发生指定的中断类型
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//使能串口
USART_Cmd(USART1,ENABLE);
}
(3)编写完串口初始化函数之后,我们需要编写中断处理函数:中断处理函数的核心思想是,当检测到中断是数据发送中断后,将发送的数据保存下来,并且在将保存下来的数据发送出去,所以我们在串口调试助手上看到的数据其实是开发板发送出去的数据,并不是接收到的数据。终端服务函数的核心代码如下:
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断中断类型
{
Res = USART_ReceiveData(USART1);//将发送的数据保存
USART_SendData(USART1,Res);//将保存的数据发送
}
(4)最后,我们便进行主函数的编写:编写相关的函数,并且将输出的数据显示出来。主函数的代码如下:
int main(void)
{
u8 t;
u8 len;
u16 times=0;
delay_init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分子组
MY_USART_init(); //串口初始化函数
LED_Init(); //
while(1)
{
if(USART_RX_STA&0x8000)//数据发送完成 {
len=USART_RX_STA&0x3fff;//获得数据长度
printf("\r\nÄú·¢Ë͵ÄÏûϢΪ:\r\n");
for(t=0;t<len;t++)
{
USART1->DR=USART_RX_BUF[t];
while((USART1->SR&0X40)==0);//等待发送结束
}
printf("\r\n\r\n");//换行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\r\nALIENTEK MiniSTM32开发板 串口实验\r\n");
printf("正点原子@ALIENTEK\r\n\r\n\r\n");
}
if(times%200==0)printf("请输入数据,以回车结束\r\n");
if(times%30==0)LED0=!LED0;//通过LED闪烁,提示系统正在运行
delay_ms(10);
}
}
}
以上就是本次实验的全部讲解内容。
说起来串口通信好像很高大上的样子,但是了解了原理后也不过如此,串口通信就到这里,你学废了吗?下篇文章见!