1.通信的基本概念
(1)串行通信和并行通信
(2)单工,半双工和全双工
(3)通信速率
单位时间内传输的比特数表示传输速度,叫做波特率(bps)
(4)通信协议(串口)
通信协议就是通信双方约定好的数据格式
2.串口的硬件连接
UART ----------------- 通用异步收发器
USART --------------- 通用同步/异步收发器
3.stm32的串口开发
(1)原理图
USB调试口连接到了CPU的PA9 PA10,它们具有串口复用的功能
(2)CPU芯片手册
外设串口的速度一定比CPU的速度慢,CPU不能一直发送数据给串口,因为串口还没发送出去,可能会导致串口堵塞;也不能一直从串口拿数据,因为串口的接受数据的速度一定会慢于CPU。
我们得查询串口的状态,接受缓冲区是否满了,发送缓冲区是否为空,传输标志是否已经结束,这个是轮询查询,前面的内容知道,轮询效率很低。比如收数据的时候,轮询了一天,也没有数据发送过来,那么一天就白干了。
发送数据往往由自己决定,是即时的,使用中断函数效率提升不大,比如放入一个数据,等发送数据缓冲区为空,就会产生一个中断提醒你,让你可以发下一个数据。这个过程和等待数据发送完是差不多的。
串口收到数据后就会产生中断,效率会比较高一点。用接收数据寄存器已满表示已经可以接收数据。
(3)串口接口的编程实现
在工程中添加串口库函数源码
1)开启GPIOA和USART1的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
2)将PA9 PA10配置为复用功能,并且映射到串口1
GPIO_Init(...); GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
3)初始化串口
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); 参数: USARTx - 哪个串口
USART_InitStruct - 串口初始化结构
typedef struct
{
uint32_t USART_BaudRate; /*!< 波特率 */
uint16_t USART_WordLength; /*!< 数据位长度 @ref USART_Word_Length */
uint16_t USART_StopBits; /*!< 停止位长度 @ref USART_Stop_Bits */
uint16_t USART_Parity; /*!< 校验方式 @ref USART_Parity */
uint16_t USART_Mode; /*!< 发送/接收模式 @ref USART_Mode */
uint16_t USART_HardwareFlowControl; /*!< 硬件流控制 @ref USART_Hardware_Flow_Control */ } USART_InitTypeDef;
4)使能串口
USART_Cmd(USART1,ENABLE);
5)数据的发送和接收
发送:
//轮询
//传入往哪个串口发送什么数据
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
//每次发送前查询上一个数据是否发送完成
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
//传入哪个串口的什么标志,返回SET表示有该标志,返回RESET表示没有该标志
//USART_FLAG_TC ----- 发送完成标志
———————————————————————————————————————————
练习:
实现串口1字符串的发送
———————————————————————————————————————————
//功能函数代码
#include <stm32f4xx.h>
#include <usart.h>
#include <stdio.h>
#include <string.h>
#include <includes.h>
//stm32开发板上运行程序,如果主机运行了调试器,程序就会使用主机的输入输出设备
//这是方式叫半主机模式,printf如果要通过串口打印,必须关闭半主机模式
#pragma import(__use_no_semihosting)
struct __FILE{
int handle;
};
FILE __stdout;
//定义_sys_exit函数避免使用半主机模式
void _sys_exit(int x)
{
x = x;
}
//重定义fputc
int fputc(int ch,FILE *F)
{
//等待上一个数据发送完成
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
//发送
USART_SendData(USART1,ch);
return ch;
}
void usart1_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//1.开启GPIOA和USART1时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//2.配置PA9 PA10为串口功能
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//高速
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_Init(GPIOA,&GPIO_InitStruct);
//PA9,PA10映射到USART
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
//3.初始化串口 8N1
USART_InitStruct.USART_BaudRate = 115200;//波特率
USART_InitStruct.USART_WordLength = USART_WordLength_8b;//8位数据位
USART_InitStruct.USART_StopBits = USART_StopBits_1;//1位停止位
USART_InitStruct.USART_Parity = USART_Parity_No;//无校验
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;//发送接收模式
//无硬件流控制
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1,&USART_InitStruct);
//4.开启串口接收中断(清除中断标志)
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//5.初始化NVIC
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x2;//抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;//响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//使能
NVIC_Init(&NVIC_InitStruct);
//.使能串口
USART_Cmd(USART1,ENABLE);
}
//发送一个字符(轮询)
void uart1_putc(char ch)
{
//等待上一个数据发送完成
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
USART_SendData(USART1,ch);
}