串行接口
- 1.串口简介
- 2.串口的工作模式
- 3.串口与并口的区别
- 4.不同电平标准的串口
- 5.开发板上的串口
- 6.USART/UART简介
- 7.USART/UART的配置
- 初始化USART1
- 发送与接收数据
- 主函数:有限状态机实现控制蜂鸣器(发送接收字符串)
1.串口简介
串口也叫做串行的接口,串行的通信接口或者串行的通讯接口,(COM接口)
串行的通信指的是数据一位一位的按顺序进行传输
操作方式简单,只需要一条数据线就可以完成数据的传输
2.串口的工作模式
- 单工模式:A------>-----B,A设备只发送数据,B设备只接收数据,数据线只有一种方向
- 半双工模式:A–>------<–B,A设备可以收发数据,B设备可以收发数据,在同一时间数据线只能有一种方向的传输
- 全双工模式:------>----------,A B,-----------<-----,A设备可以收发数据,B设备可以收发数据,在同一时间A B设备既可以发送数据,也可以接收数据
3.串口与并口的区别
串口:是指数据一位一位的按顺序传输数据
并口:是指数据多位多位的传输数据
并不说并口可以一次传输多位数据,传输的速度就要比串口快,正好相反串口的传输速度要比并口快,因为并口的多条数据线之间互相有干扰,所以传输速度受到了限制
4.不同电平标准的串口
注意:如果两个设备需要通过串口进行通信,首先要确保电平标准一致,如果电平标准不一样需要使用电平转换模块MAX232…
RS485电平标准(工业<抗干扰能力极强>) ,距离1000米左右,如果在单工或者半双工模式下需要两条数据线,如果在全双工模式下需要4条数据线,RS485传输的是两条数据线的电压差
5.开发板上的串口
在STM32F103RBT6芯片中串口非常丰富,USART/UART I²C SPI I²S CAN …
6.USART/UART简介
由于USART/UART中只有数据线,没有时钟线所以时钟不能自动调节,
USART : 通用的同步异步收发器,相当于即支持同步模式也支持异步模式
UART : 通用的异步收发器,只支持异步模式
同步 : 在同步模式下是以数据段的格式进行交互数据,无论是位与位之间还是数据字节与字节之间都需要保持同步,例:“Hello” -> ‘H’ 1s ‘e’ 1s ‘l’ 1s ‘l’ 1s ‘o’
异步 : 在异步模式下是以数据帧的格式进行交互数据,位与位之间必须保持同步的,但是数据帧与数据帧之间可以是异步的通信,例:“YES” -> ‘Y’ 1s ‘E’ 1min ‘S’ ----- ‘E’ -> 69 -> 01000101
7.USART/UART的配置
注意:如果两个设备需要通过串口进行通信,其次要确保波特率一致
115200 波特率
8 8个数据位
N 没有奇偶校验
1 1个停止位
在STM32F103RBT6芯片中的USART/UART,有3个USART/UART:
USART1 纽扣电池的上面
USART2 无线模块的接口
USART3 扩展IO的接口
初始化USART1
void usart_1_init(void)//用来初始化USART1的函数
{
GPIO_InitTypeDef Gpio_Value;//定义了GPIO初始化结构体类型的变量
USART_InitTypeDef Usart_Value;//定义了USART初始化结构体类型的变量
NVIC_InitTypeDef Nvic_Value;//定义了NVIC初始化结构体类型的变量
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
//通过APB2总线使能GPIOA组和USART1的时钟
Gpio_Value.GPIO_Mode = GPIO_Mode_AF_PP;//选择了推挽的复用模式
Gpio_Value.GPIO_Pin = GPIO_Pin_9;//选择了9号管脚
Gpio_Value.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速率
GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化PA9管脚
Gpio_Value.GPIO_Mode = GPIO_Mode_IN_FLOATING;//选择了浮空的输入模式
Gpio_Value.GPIO_Pin = GPIO_Pin_10;//选择了10号管脚
GPIO_Init(GPIOA, &Gpio_Value);//按照上述配置初始化PA10管脚
Usart_Value.USART_BaudRate = 115200;//选择了115200的波特率
Usart_Value.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//选择了关闭硬件流控
Usart_Value.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//选择了发送和接收模式
Usart_Value.USART_Parity = USART_Parity_No;//选择了没有奇偶校验
Usart_Value.USART_StopBits = USART_StopBits_1;//选择了1个停止位
Usart_Value.USART_WordLength = USART_WordLength_8b;//选择了8个数据位
USART_Init(USART1, &Usart_Value);//按照上述配置初始化USART1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置组优先级和子优先级的所占比例
Nvic_Value.NVIC_IRQChannel = USART1_IRQn;//选择了USART1的中断号
Nvic_Value.NVIC_IRQChannelCmd = ENABLE;//选择了使能该中断
Nvic_Value.NVIC_IRQChannelPreemptionPriority = 2;//选择了组优先级的级别
Nvic_Value.NVIC_IRQChannelSubPriority = 2;//选择了子优先级的级别
NVIC_Init(&Nvic_Value);//按照上述配置初始化NVIC
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//使能了USART1的接收数据触发中断
USART_Cmd(USART1, ENABLE);//使能了USART1的功能
}
发送与接收数据
void usart_1_send_byte(u8 data)//发送一个字节的数据
{
USART_SendData(USART1, data);//通过USART1把data变量存储的数据进行发送
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//以死等的方式等待USART1的发送数据成功
USART_ClearFlag(USART1, USART_FLAG_TC);//清除USART1的发送数据成功的标志状态
}
void usart_1_send_data(char *buf)//发送一个字符串
{
while(*buf)//判断buf指针指向的是否是'\0'
{
usart_1_send_byte(*buf);//发送有效字符
buf++;//指针偏移到下一个字符
}
}
u8 usart_1_recv_byte(void)//接收一个字节的数据(轮询的方式)
{
u8 ret = 0;//用于保存USART1接收到的数据
if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)//判断USART1是否接收到了数据
{
ret = USART_ReceiveData(USART1);//通过ret变量获取USART1接收到的数据
USART_ClearFlag(USART1, USART_FLAG_RXNE);//清除USART1接收数据寄存器不为空的标志
}
return ret;//把接收到的数据返回
}
void USART1_IRQHandler(void)//USART1的中断处理函数
{
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
//判断是否是由USART1的接收数据触发的中断
{
u1_h(USART_ReceiveData(USART1));
//接收USART1的数据,并把接收到的数据以传参的形式传递给回调函数
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//清除USART1的接收数据的中断标志状态
}
}
void set_usart1_handler(usart1_handler h)//设置回调函数
{
u1_h = h;//把形参h存储的地址转存到全局的函数指针中
}
主函数:有限状态机实现控制蜂鸣器(发送接收字符串)
/*
"ON"
"OFF"
"ONE"
*/
#define O_FLAG 0
#define N_FLAG 1
#define F_FLAG 2
int flag = O_FLAG;//默认等于O_FLAG的状态
void recv_handler(u8 c)//解析数据的函数
{
switch(flag)
{
case O_FLAG :
if(c == 'O')
{
flag = N_FLAG;
}
break;
case N_FLAG :
if(c == 'N')
{
buzzer_on();
flag = O_FLAG;
}
else if(c == 'F')
{
flag = F_FLAG;
}
else
{
flag = O_FLAG;
}
break;
case F_FLAG :
if(c == 'F')
{
buzzer_off();
}
flag = O_FLAG;
break;
}
}
int main(void)
{
char dht_buf[5] = {0};//该数组用于存储DHT11采集到的数据
int dht_value = 0;//该变量用于存储DHT11温湿度结合的数据
int i = 500;//循环变量
led_init();//调用LED灯初始化的函数
buzzer_init();//调用蜂鸣器初始化的函数
button_init();//调用功能按键初始化的函数
delay_init();//调用系统定时器初始化的函数
eint_init();//调用按键中断初始化的函数
dht_init();//调用DHT11初始化的函数
ldt_init();//调用数码管初始化的函数
usart_1_init();//调用USART1初始化的函数
set_usart1_handler(recv_handler);//设置回调函数
while(1)
{
get_dht_value(dht_buf);//获取DHT11传感器采集到的数据
//dht_buf[0] 湿度的整数 dht_buf[1] 湿度的小数
//dht_buf[2] 温度的整数 dht_buf[3] 温度的小数 dht_buf[4] 校验和
printf("Hum:%d Temp:%d\n", dht_buf[0], dht_buf[2]);
dht_value = dht_buf[0] * 100 + dht_buf[2];//把湿度的整数以及温度的整数整合成一个4位数据
while(i--)
digit_show_data(dht_value);//通过数码管显示温湿度数据
i = 500;
}
}