文章目录
- 前言
- 一、介绍部分
- 通信接口
- 术语解释
- 串口通信简介
- 硬件电路
- 电平标准
- 串口参数
- 串口时序
- USART简介
- USART框图
- USRAT基本结构
- 数据帧
- 起始位检测
- 波特率发生器
- CH340G
- 二、实例部分
- 使用串口发送数据
- 接线图
- 代码实现
- 重定向printf需要勾上Use MicroLIB
- 中文不乱码方法
- 串口的发送与接收数据
- 线路连接与上面一致
- 代码实现
前言
串口通信(Serial Communications)的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。本文主要接收使用串口发送接收数据,波特率设置,串口的基本时序等。
一、介绍部分
通信接口
术语解释
串口通信简介
硬件电路
电平标准
串口参数
串口时序
USART简介
USART框图
USRAT基本结构
数据帧
起始位检测
在受到噪声影响后,采用2:1策略,选择更多的作为所接收到的数据,并使噪声标志位NE置1
波特率发生器
CH340G
二、实例部分
使用USART1来作为例子,根据引脚定义,选择正确的接口
使用串口发送数据
接线图
代码实现
配置串口Serial.c
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
void Serial_Init(void){
// 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
// 初始化引脚,发送数据引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // A9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化串口配置
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Tx; // 串口模式,发送
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长
USART_Init(USART1,&USART_InitStructure);
// USART1使能
USART_Cmd(USART1,ENABLE);
}
// 发送函数
void USART_SendByte(uint8_t Byte){
USART_SendData(USART1,Byte);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
uint8_t i = 0;
for(i=0;i<Length;i++){
USART_SendData(USART1,Array[i]);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
// 发送字符串函数
void USART_SendString(uint8_t *String){
uint8_t i = 0;
for(i=0;String[i]!='\0';i++){
USART_SendData(USART1,String[i]);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
uint32_t Result = 1;
while(Y--){
Result *= X;
}
return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
uint8_t i = 0;
for(i=0;i<Length;i++){
USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
USART_SendByte(ch);
return ch;
}
// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg; // 可变参数列表
va_start(arg, format); // 从format开始接收可变参数
vsprintf(String, format, arg);
va_end(arg);
USART_SendString((uint8_t*)String);
}
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
int main(void)
{
OLED_Init();
Serial_Init();
//USART_SendByte();
// uint8_t Array[] = {0x41,0x42,0x43,0x44};
// USART_SendArray(Array,4);
// uint8_t String[] = {"hello world"};
// USART_SendString(String);
// USART_SendNum((uint32_t)12345,5);
// printf("Num = %d\r\n",666);
// char String[100];
// sprintf(String,"Num = %d\r\n",666);
// USART_SendString((uint8_t*)String);
Serial_Printf("一程山水");
while (1)
{
}
}
重定向printf需要勾上Use MicroLIB
中文不乱码方法
- 代码与串口都使用utf8格式,并在如下图位置加上–no-multibyte-chars
- 使用GB2312支持中文编码格式,串口使用GBK编码格式接收即可。
串口的发送与接收数据
线路连接与上面一致
代码实现
串口配置Serial.c
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t RxData;
uint8_t RxFlag;
void Serial_Init(void){
// 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
// 初始化引脚
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // A9 发送数据
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // A10 接收数据
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 50Hz翻转速度
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 初始化串口配置
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; // 串口波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用流控
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // 串口模式,发送+接收
USART_InitStructure.USART_Parity = USART_Parity_No; // 无校验
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 选择一位停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 不需要校验位,八位字长
USART_Init(USART1,&USART_InitStructure);
// 开启中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//初始化NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 分组
NVIC_InitTypeDef NVIC_InitStructure;
// 中断通道
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
// 中断通道使能
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 响应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
// USART1使能
USART_Cmd(USART1,ENABLE);
}
// 发送函数
void USART_SendByte(uint8_t Byte){
USART_SendData(USART1,Byte);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
// 发送数组函数
void USART_SendArray(uint8_t *Array,uint16_t Length){
uint8_t i = 0;
for(i=0;i<Length;i++){
USART_SendData(USART1,Array[i]);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
// 发送字符串函数
void USART_SendString(uint8_t *String){
uint8_t i = 0;
for(i=0;String[i]!='\0';i++){
USART_SendData(USART1,String[i]);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
// 返回X的Y次方
uint32_t Serial_Pow(uint32_t X,uint32_t Y){
uint32_t Result = 1;
while(Y--){
Result *= X;
}
return Result;
}
// 发送数字函数
void USART_SendNum(uint32_t Num,uint16_t Length){
uint8_t i = 0;
for(i=0;i<Length;i++){
USART_SendByte(Num / Serial_Pow(10,Length-i-1) % 10 + 0x30);
// 等待写入完成,写入完成之后会将标志位自动清0
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
}
}
//重定向fputc函数,fputc是printf函数的底层,printf通过不停的调用fputc来达到输出的效果
//重定向到串口
int fputc(int ch,FILE *f){
USART_SendByte(ch);
return ch;
}
// 封装使用sprintf输出到串口
void Serial_Printf(char *format, ...)
{
char String[100];
va_list arg; // 可变参数列表
va_start(arg, format); // 从format开始接收可变参数
vsprintf(String, format, arg);
va_end(arg);
USART_SendString((uint8_t*)String);
}
// 获取RxFlag
uint8_t USART_GetRxFlag(void){
if(RxFlag == 1){
RxFlag = 0;
return 1;
}
return 0;
}
// 获取RxData
uint8_t USART_GetRxData(void){
return RxData;
}
//中断函数
void USART1_IRQHandler(void){
if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET){
RxData = USART_ReceiveData(USART1);
RxFlag = 1;
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
uint8_t Serial_RxData;
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, "RxData:");
Serial_Init();
while (1)
{
if (USART_GetRxFlag() == 1)
{
Serial_RxData = USART_GetRxData();
USART_SendByte(Serial_RxData);
OLED_ShowHexNum(1, 8, Serial_RxData, 2);
}
}
}