STM32——15.串口发送与接收&打印函数重定向
串口通信
通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统。
通信协议:制定通信的规则,通信双方按照协议规则进行数据收发。
| 名称 | 引脚 | 双工 | 时钟 | 电平 | 设备 |
|---|---|---|---|---|---|
| USART | TX、RX | 全双工 | 异步 | 单端 | 点对点 |
| I2C | SCL、SDA | 半双工 | 同步 | 单端 | 多设备 |
| SPI | SCLK、MOSI、MISO、CS | 全双工 | 同步 | 单端 | 多设备 |
| CAN | CAN_H、CAN_L | 半双工 | 异步 | 差分 | 多设备 |
| USB | DP、DM | 半双工 | 异步 | 差分 | 点对点 |
串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信。
单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。
硬件电路
简单双向串口通信有两根通信线(发送端TX和接收端RX)。
TX与RX要交叉连接。
当只需单向的数据传输时,可以只接一根通信线。
当电平标准不一致时,需要加电平转换芯片

电平标准
电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
TTL电平:+3.3V或+5V表示1,0V表示0。
RS232电平:-3~-15V表示1,+3~+15V表示0。
RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)(理论可达一千多米)
串口参数及时序
波特率:串口通信的速率
起始位:标志一个数据帧的开始,固定为低电平
数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行。
校验位:用于数据验证,根据数据位计算得来
停止位:用于数据帧间隔,固定为高电平


USART简介
USART(Universal Synchronous/Asynchronous Receiver/Transmitter)通用同步/异步收发器。
USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里。
自带波特率发生器,最高达4.5Mbits/s
可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)
可选校验位(无校验/奇校验/偶校验)
支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN
STM32F103C8T6 USART资源: USART1、 USART2、 USART3

USART基本结构(初始化通常根据这个来)


---------------------Serial.c------------------------------------------------------------------
#include "stm32f10x.h" // Device header
#include <stdio.h>
/*
看基本结构图写步骤:
1.开启时钟,把需要用到的USART和GPIO时钟打开。
2.GPIO初始化,把TX配置成复用输入,RX设置成输入
3.USART初始化,使用结构体初始化。
4.开启发送功能,USART(如果需要接受就使用中断)
*/
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStruct;
USART_InitStruct.USART_BaudRate =9600;
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStruct.USART_Mode = USART_Mode_Tx;
USART_InitStruct.USART_Parity = USART_Parity_No;
USART_InitStruct.USART_StopBits = USART_StopBits_1;
USART_InitStruct.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1 , &USART_InitStruct);
USART_Cmd(USART1 , ENABLE);
}
//发送一个字节
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1 , Byte);
//判断标志位是否为0,防止数据覆盖
while (USART_GetFlagStatus(USART1 , USART_FLAG_TXE) == RESET);
}
//发送一个数组
void Serial_SendArray(uint8_t *Array , uint16_t Length)
{
uint8_t i;
for(i = 0 ; i < Length ; i++)
{
Serial_SendByte(Array[i]);
}
}
//发送一个字符串
void Serial_SendString(char *String)
{
uint8_t i;
for(i = 0 ; String[i] != '\0' ; i++)
{
Serial_SendByte(String[i]);
}
}
//求取次方结果
uint32_t Get_Pow(uint8_t x , uint8_t y)
{
uint32_t Result = 1;
while(y--)
{
Result *= x;
}
return Result;
}
//发送一个数字
void Serial_SendNumber(uint32_t Num , uint8_t Length)
{
//将数字,一个一个都提取出来,在单独发送
//362 / 100 = 3.62 % 10 = 3
uint8_t i;
for(i = 0 ; i < Length ; i++)
{
Serial_SendByte(Num / Get_Pow(10 , Length - i - 1) % 10 + '0'); //0是为了显示数字
}
}
//重写fputc函数,完成重定向,将打印的数据显示到串口
//还有升级版,重新看视频
int fputc(int ch , FILE *f)
{
Serial_SendByte(ch);
return ch;
}
---------------------Serial.h------------------------------------------------------------------
#ifndef __SERIAL_H
#define __SERIAL_H
#include <stdio.h>
void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array , uint16_t Length);
void Serial_SendString(char *String);
void Serial_SendNumber(uint32_t Num , uint8_t Length);
#endif
---------------------main.c------------------------------------------------------------------
#include "stm32f10x.h"
#include "OLED.h"
#include "Serial.h"
int main(void)
{
OLED_Init();
Serial_Init();
// Serial_SendByte(0x41);
// Serial_SendByte('B');
// uint8_t arr[] = {0x51,0x52,0x53,0x54};
// Serial_Array(arr , 4);
// Serial_SendString("Hello world!");
// Serial_SendNumber(18990925 , 8);
//printf重定向
//printf("Num = %d\r\n" , 888);
//显示中文,将c/c++那个设置哪里填上--no-multibyte-chars 。还有记得选utf-8
//串口助手也设置utf-8就可以了。
printf("星辰物语");
while(1)
{
}
}
作者:m0_48261292