1.通信接口相关知识:
(1)处理器与外界设备通信的两种方式:
1)并行通信:
-
传输原理:数据各个位同时传输;
-
优点:速度快;
-
缺点:占用引脚资源多;
2)串行通信:
- 传输原理:数据按位顺序传输;
- 优点:占用引脚资源少;
- 缺点:速度相对较慢;
(2)按照数据传送方向分为:
- 单工:数据传输只支持数据在一个方向上传输;
- 半双工:允许数据在两个方向上传输,但在某一时刻,只允许数据在一个方向上传输,实际是一种切换方向的单工通信;
- 全双工:允许数据同时在两个方向上传输,所以全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力;
2.串行通信的通信方式:
- 同步通信:带时钟同步信号传输;如SPI、IIC;
- 异步通信:不带时钟同步信号;如UART(通用异步收发器)、单总线;
3.常见的串行通信接口:
4.STM32F103串行通信:
(1)STM32的串行通信接口:
- UART:通用异步收发器;
- USART:通用同步异步收发器;
(2)UART异步通信方式引脚连接方法:
- RED:数据输入引脚。数据接收;
- TXD:数据发送引脚。数据发送;
(3)UART异步通信方式特点:
- 全双工异步通信;
- 分数波特率发生器系统,提供精确的波特率;发送和接收共用的可编程波特率,最高可达4.5Mbit/s;
- 可编程额数据字节长度(8位或9位);
- 可配置的停止位(支持1位或者2位停止位);
- 可配置的使用DMA多缓冲器通信;
- 单独的发送器和接收器使能位;
- 检测标志:1.接收缓冲器、2.发送缓冲器、3.传输结束标志;
- 多个带标志的中断源,触发中断;
- 其他:校验控制,四个错误检测标志;
(4)串口通信过程:
(5)STM32串口异步通信需要定义的参数:
- 起始位;
- 数据位(8位或9位);
- 奇偶校验位(第九位);
- 停止位(1,15,2位);
- 波特率设置;
5.库函数实现串口通信:
(1)串口配置的步骤:
- 串口时钟使能,GPIO时钟使能;
- 串口复位(不是必须);
- GPIO端口模式设置;
- 开启中断并且初始化NVIC(如果需要开启中断才需要该不步骤);
- 使能串口;
- 编写中断处理函数;
- 串口数据收发;
- 串口传输状态获取;
(2)串口相关原理图:
(3)实现结果:
STM32通过USART1实现与PC对话,STM32的USART1收到PC发来的数据后原封不动的返回给PC显示。同时使用LED0指示灯不断闪烁提示系统正常运行。
1)主函数:
#include "delay.h"
#include "led.h"
#include "usart1.h"int main(){u8 i=0; u16 length=0;u16 temp=0;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组delay_init(); //延时初始化LED_Init(); //LED初始化usart1_Init(9600); //串口初始化while(1){if(USART1_RX_STA&0x8000) //判断是否接收完成->这里表示接收完成{length=USART1_RX_STA&0x3fff; //接收到的数据长度for(temp=0;temp<length;temp++){USART_SendData(USART1,USART1_RX_BUF[temp]); //将接收到的数据,发送出去while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); //判断是否已经发送完成 }USART1_RX_STA=0; //发送完成之后,对USART1_RX_STA进行清零}i++;if(i%20==0){LED0=!LED0;}delay_ms(10);}
}
2)头文件:
#ifndef __USART1_H
#define __USART1_H#define USART1_REC_LEN 200typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;extern u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓存的数据容器
extern u16 USART1_RX_STA; //标志位void usart1_Init(u32 bund); //串口1初始化#endif
3)串口1初始化函数:
#include "usart1.h"
#include "stm32f10x.h"/*功能:串口1的初始化变量:bund:波特率返回值:无*/
void usart1_Init(u32 bund)
{GPIO_InitTypeDef GPIO_InitStruct;USART_InitTypeDef USART_InitStruct;NVIC_InitTypeDef NVIC_InitStruct;//1.GPIO时钟使能和端口复用时钟使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);//2.配置GPIO->TX-PA9GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; //PA9GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //输出速度GPIO_Init(GPIOA,&GPIO_InitStruct);//配置GPIO->RX-PA10GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10; //PA9GPIO_Init(GPIOA,&GPIO_InitStruct);//3.初始化串口参数USART_InitStruct.USART_BaudRate=bund; //设置波特率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; //1位停止位USART_InitStruct.USART_WordLength=USART_WordLength_8b; //字长8位,无奇偶校验位USART_Init(USART1,&USART_InitStruct);//4.设置串口中断优先级,使能串口中断通道NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn; //设置串口1通道NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级NVIC_InitStruct.NVIC_IRQChannelSubPriority=2; //子优先级NVIC_Init(&NVIC_InitStruct);//5.设置串口中断类型USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //串口1,接收中断,使能//6.使能串口USART_Cmd(USART1,ENABLE);}/*功能:串口1中断服务函数变量:无返回值:无设置通信方式-注意:1.0x0A(换行),0x0D(回车);2.识别累计接收的数据长度以及是否接收到0x0D和0x0A;当连续接收到0x0D和0x0A才算接收完成;3.USART1_RX_STA的15位为1,则为接收完成的标志;USART1_RX_STA的14位为1,则接收到0x0D;4.0~13位,表示接收的有效数据字节;
*/u8 USART1_RX_BUF[USART1_REC_LEN]; //接收缓存的数据容器
u16 USART1_RX_STA=0; //标志位void USART1_IRQHandler(void)
{u8 data=0;if(USART_GetITStatus(USART1,USART_IT_RXNE)) //获取串口接收中断标志{data=USART_ReceiveData(USART1); //将串口1接收到的数据,存储到data中;if((USART1_RX_STA&0x8000)==0) //判断是否接收完成->这里是接收未完成{ if((USART1_RX_STA&0x4000)) //判断是否接收到0x0D->这里是接收到了0x0D{if(data==0x0A) //判断接收到0X0D后,下一次接收的是否是0X0A->这里是已经接收到0x0A{USART1_RX_STA|=0x8000; //将USART1_RX_STA最高位设置为1,表示接收完成}else //未接收到0x0A{USART1_RX_STA=0; //接收错误,置0}}else //未接收到0x0D{if(data==0x0D) //下一次接收到0x0D时{USART1_RX_STA|=0x4000; //将USART1_RX_STA的第14位设置为1}else //下一次并未接收到0X0D时{USART1_RX_BUF[USART1_RX_STA&0x3fff]=data; //将data内的数据,放入USART1_RX_BUF中USART1_RX_STA++;if(USART1_RX_STA>(USART1_REC_LEN-1)) //判断累计的次数是否大于数组极限容量值->这里表示超过{USART1_RX_STA=0; //接收错误,置0}}}}}
}
6.串口通信printf
(1)使用结果:
在上诉实验中进行改进,对printf进行重定向,再通过printf函数将信息打印到串口调试助手上显示,同时LED0指示灯不断闪烁,表示系统正常运行。
(2)库函数实现:
1)主函数:在主函数中添加printf打印;
2)头文件:在头文件中添加#include "stdio.h";
3)串口初始化函数:对printf进行重定向;
注意:
在串口通信中需要使用printf打印时,需要勾选Use Micro LIB否则将无法打印出信息;