一、串口通信协议简介
(0)串口线及电平简介
(1)物理层
1》RS232标准
2》USB转串口
3》原生的串口到串口
(2)协议层
起始位:由1个逻辑0的数据位表示。
数据位:在起始位后紧接着的就是有效数据,有效数据的长度常被约定为 5、 6、 7 或 8 位长。
校验位:可选,为的是数据的抗干扰性。 校验方法分为:
(1)奇校验(odd)
有效数据和校验位中“ 1”的个数为奇数。
比如一个 8 位长的有效数据为: 01101001,此时总共有 4 个“ 1”,为达到奇校验效果,校验位为“ 1”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。
(2)偶校验(even)
有效数据和校验位中“ 1”的个数为偶数。
比如一个 8 位长的有效数据为: 01101001,此时总共有 4 个“ 1”,为达到偶校验效果,校验位为“ 0”,最后传输的数据将是 8 位的有效数据加上 1 位的校验位总共 9 位。
(3)0校验(space)
是不管有效数据中的内容是什么,校验位总为“ 0”。
(4)1校验(mark)
是不管有效数据中的内容是什么,校验位总为“ 1”。
(5)无校验(noparity)
数据包中不包含校验位。
停止位:由 0.5、 1、 1.5 或 2 个逻辑 1 的数据位表示。
二、原理图
三、串口功能框图
(1)引脚
TX:数据发送
RX:数据接收
SCLK:时钟,仅同步通信时使用
nRTS:请求发送
nCTS:允许发送
(2)数据寄存器
9位有效,包含一个发送数据寄存器TDR和一个接收数据寄存器RDR。一个地址对应了两个物理寄存器。
(3)控制器
标志:
TXE---发送完成,当该位被置1的时候,表示 USART_DR 内的数据已经被发送完成了。
TXEIE---发送完成时产生中断。
TC---发送完成,当该位被置1的时候,表示 USART_DR 内的数据已经被发送完成了。
TCIE---发送完成时产生中断。
RXNE---读数据寄存器非空,当该位被置 1 的时候,就是提示已经有数据被接收到了,并
且可以读出来了。
RXNEIE---接收数据寄存器非空时产生中断。
(4)波特率
每秒钟要发送多少数据。
四、结构体初始化
typedef struct
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
USART_BaudRate:设置串口波特率。
115200
USART_WordLength:设置串口字长。
USART_WordLength_8b
USART_StopBits:设置串口停止位。
USART_StopBits_1
USART_Parity:设置串口校验位。
USART_Parity_No
USART_Mode:设置模式。
USART_Mode_Tx
USART_Mode_Rx
USART_HardwareFlowControl:设置硬件流控。
USART_HardwareFlowControl_None
五、常用固件库函数
(1)配置GPIO为具体的第二功能
void GPIO_PinAFConfig (GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);
(2)中断配置函数
void USART_ITConfig (USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
(3)串口使能函数
void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
(4)数据发送函数
//将数据data写入到数据寄存器USART_DR中
void USART_SendData (USART_TypeDef* USARTx, uint16_t Data);
(5)数据接收函数
//从数据寄存器USART_DR中读取接收到的数据
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
(6)中断状态位获取函数
//读取状态寄存器USART_SR中指定位的值
ITStatus USART_GetITStatus (USART_TypeDef* USARTx, uint16_t USART_IT);
六、程序
bsp_usart.h文件
#ifndef __BSP_USART_H__
#define __BSP_USART_H__
#include "stm32f4xx_conf.h"
//USART配置
extern void USART_Config(void);
//发送一个字符
extern void USART_SendByte(uint8_t ch);
//发送一个字符串
extern void USART_SendString(char *str);
#endif
bsp_usart.c文件
#include "./usart/bsp_usart.h"
#include "stdio.h"
/*
Tx---PA9;Rx---PA10
*/
/*******************
功能:配置串口
参数:无
返回值:无
********************/
void USART_Config(void)
{
GPIO_InitTypeDef initValue;
USART_InitTypeDef usartInitValue;
NVIC_InitTypeDef nvicInitValue;
/*1、打开时钟*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/*2、配置GPIO的复用功能*/
initValue.GPIO_Mode = GPIO_Mode_AF;
initValue.GPIO_OType = GPIO_OType_PP;
initValue.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
initValue.GPIO_PuPd = GPIO_PuPd_NOPULL;
initValue.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&initValue);
/*3、选择复用管脚*/
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
/*4、初始化串口*/
usartInitValue.USART_BaudRate = 115200;
usartInitValue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usartInitValue.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
usartInitValue.USART_Parity = USART_Parity_No;
usartInitValue.USART_StopBits = USART_StopBits_1;
usartInitValue.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&usartInitValue);
/*5、配置NVIC*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
nvicInitValue.NVIC_IRQChannel = USART1_IRQn;
nvicInitValue.NVIC_IRQChannelCmd = ENABLE;
nvicInitValue.NVIC_IRQChannelPreemptionPriority = 1;
nvicInitValue.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&nvicInitValue);
/*6、打开串口的接收中断*/
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
/*7、使能串口*/
USART_Cmd(USART1,ENABLE);
}
/********************
功能:发送一个字符
参数:要发送的字符
返回值:无
*********************/
void USART_SendByte(uint8_t ch)
{
/*1、发送字符*/
USART_SendData(USART1,ch);
/*2、等待字符发送完成*/
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
/**********************
功能:发送一个字符串
参数:要发送的字符串
返回值:无
***********************/
void USART_SendString(char *str)
{
do
{
USART_SendByte(*str);
str++;
}while(*str != '\0');
/*2、等待发送完成*/
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
}
/*
功能:重定向C库函数printf到串口,重定向后可使用printf函数
参数:ch---要发送的数据
返回值:发送的数据
*/
int fputc(int ch,FILE *f)
{
/*1、发送一个字节的数据到串口*/
USART_SendData(USART1,(uint8_t)ch);
/*2、等待数据的发送完成*/
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
return ch;
}
/*
功能:重定向C库函数scanf到串口,重定向后可使用scanf、getchar等函数
参数:
返回值:接收到的数据
*/
int fgetc(FILE *f)
{
/*1、等待串口输入数据*/
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == RESET);
/*2、接收数据*/
return (int)USART_ReceiveData(USART1);
}
main.c文件
#include "delay.h"
#include "stdio.h"
#include "./LED/led.h"
#include "./USART/usart.h"
int main(void)
{
uint8_t ch;
//配置串口
USART_Config();
//发送一个字符
USART_SendByte('A');
//发送一个字符串
USART_SendString("今天是个好日子!!! \r\n");
//检验printf函数
printf("你的声音真好听!!! \r\n");
//检验scanf函数
scanf("%c",&ch);
while(1)
{
if(ch == '0')
{
LED_ON(1);
LED_ON(3);
}
}
}
stm32f4xx_it.c文件
/***********************************
功能:USART1中断服务函数
参数:无
返回值:无
************************************/
void USART1_IRQHandler(void)
{
uint8_t ch;
/*1、判断是否由于接收数据产生的中断*/
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
{
/*2、接收数据*/
ch = USART_ReceiveData(USART1);
/*3、将接收到的数据发送出去*/
USART_SendData(USART1,ch);
/*4、清除中断标志位*/
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}