目录
1.串口
(1)串口,其实就是个通信接口
分为两类:Tx和Rx(传输引脚和接收引脚)
(2)串口组成
空闲状态,起始位,数据位(最后一位校验位可选),停止位,空闲状态(或者继续开始起始位)
注意:十进制转二进制可以直接使用加法得到,下图27;数据可以是数字(十转2)或者单词(ASCAII);中间的数据位可选8-9位,停止位选择也不唯一;特别注意:数据发送的时候从右往左,接收的时候从左往右接收(原因是下面讲到的移位寄存器的原理)
(3)数据位的22分类
数据位8-9,最后一位的有无校验位,所以最后分成4种
(4)校验位的分类
奇校验or偶校验:如果当前是奇校验,发送方如果数据位除了校验位有偶数个1,那么校验位就设置为1,总共就是奇数个1,传到接收方接收如果总共是奇数个1,就是正确的。




2.USART模块(U ra te)


(1)单片机的串口(这里有串口1,串口2,串口3)

(2)使用者只需发送的时候往发送寄存器写东西就行,他会自己给发送出前面学习的起始位,数据位等等格式的数据。接收的时候在接收寄存器接收数据就行。下图是usart模块的内部结构框图

(3)移位寄存器的发送(发送后低位在前,高位在后)和接收(接收后高位在后,低位在前)
串并转换:发送的时候并行写入发送寄存器,之后并且进入移位寄存器,然后移位寄存器串行的一个个移位输出串口数据帧格式的数据。同理接收的时候串行接收数据,等移位寄存器一个个移进来数据就直接并行写入接收数据寄存器。


(4)前面第一部分学习的串口的起始位,数据位等等总的来说是串口数据帧的格式的定义
(5)波特率的设置靠分频系数来得到,该分频系数存储在波特率寄存器(后面代码的时候直接写想要的波特率就行,因为底层会自动计算该系数)

(6)USART初始化编程
编程思路:很简单,首先就是片上外设开启必须要使用的时钟,之后就是初始化的两参数:类型名称和结构体,结构体从GPIO的老三样(G、P、IO代表输入输出,所以很好记就三个参数)变成了五大参数(很好记,你就即USART有几个单词不就有几个初始化配置)。
#include "stm32f10x.h"
#include "Delay.h"
int main(void)
{
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
// GPIO_InitTypeDef GPIO_InitStruct={0};
// GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
// GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;
// GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;
//
// GPIO_Init(GPIOC,&GPIO_InitStruct);//初始化引脚0
//
// GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
// GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
//
// GPIO_Init(GPIOC,&GPIO_InitStruct);//初始化引脚1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef usart_initStruct={0};
usart_initStruct.USART_BaudRate=115200;
usart_initStruct.USART_Mode=USART_Mode_Tx | USART_Mode_Rx;
usart_initStruct.USART_WordLength=9;
usart_initStruct.USART_StopBits=USART_StopBits_1;
usart_initStruct.USART_Parity=USART_Parity_No;
USART_Init(USART1,&usart_initStruct);
while(1)
{
}
}


3.初始化串口的IO引脚


首先,前面学习了什么是串口,单片机上的串口USART以及怎么初始化编程,这里就是怎么在单片机上找到串口的引脚位置,以及找到了引脚,那么引脚的模式等参数又是怎么设置的。
(1)一般引脚就看标准的这两就行
(2)Tx,Rx位于哪个引脚就得去数据手册的引脚章节,找到当前使用的对应单片机上的引脚情况
答案就是位于复用模式(一般是cpu直接操作引脚,复用则CPU-外设(比如串口模块)-引脚发送串口数据帧格式的数据)下的
默认:PA9,PA10
重映射为:PB6,PB7
从前面知道了引脚的位置,那剩下的GPIO的两大参数怎么设置
就要看你选择的是串口的什么模式(普遍是全双工,以及Rx的全双工的浮空输入和上拉输入默认一般选择上拉输入,因为上拉默认高电压,等价于前面说的空闲状态,不像浮空输入会像天线一样高/低电压变化)
引脚分布表在数据手册的引脚部分;重映射表在参考手册的GPIO的重映射部分;参数的设置在参考手册的GPIO的外设配置部分。







(5)默认的Rx,Tx编程

(6)重映射的Rx,Tx
USART 模块的使能,其实就是让 MCU 内部的 USART 外设从“断电/停止”状态进入工作状态,让它开始响应你对串口的读写操作。

代码:
#include "stm32f10x.h"
#include "Delay.h"
int main(void)
{
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
// USART_InitTypeDef usart_initStruct={0};
// usart_initStruct.USART_BaudRate=115200;
// usart_initStruct.USART_Mode=USART_Mode_Tx | USART_Mode_Rx;
// usart_initStruct.USART_WordLength=9;
// usart_initStruct.USART_StopBits=USART_StopBits_1;
// usart_initStruct.USART_WordLength=USART_Parity_No;
// USART_Init(USART1,&usart_initStruct);
//
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
// GPIO_InitTypeDef gpio_initStruct={0};
// gpio_initStruct.GPIO_Pin=GPIO_Pin_9;
// gpio_initStruct.GPIO_Mode=GPIO_Mode_AF_PP;
// gpio_initStruct.GPIO_Speed=GPIO_Speed_10MHz;
//
// GPIO_Init(GPIOA,&gpio_initStruct);
// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
// gpio_initStruct.GPIO_Pin=GPIO_Pin_10;
// gpio_initStruct.GPIO_Mode=GPIO_Mode_IPU;
//
// GPIO_Init(GPIOA,&gpio_initStruct);
//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef gpio_initStruct2={0};
gpio_initStruct2.GPIO_Pin=GPIO_Pin_6;
gpio_initStruct2.GPIO_Mode=GPIO_Mode_AF_PP;
gpio_initStruct2.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&gpio_initStruct2);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
gpio_initStruct2.GPIO_Pin=GPIO_Pin_7;
gpio_initStruct2.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&gpio_initStruct2);
while(1)
{
}
}
疑惑解答:
问:这段代码我的问题是:gpio_initStruct2.GPIO_Pin=GPIO_Pin_7; gpio_initStruct2.GPIO_Mode=GPIO_Mode_IPU;
这两句代码执行后,那原本的GPIO_InitTypeDef gpio_initStruct2={0}; gpio_initStruct2.GPIO_Pin=GPIO_Pin_6; gpio_initStruct2.GPIO_Mode=GPIO_Mode_AF_PP; gpio_initStruct2.GPIO_Speed=GPIO_Speed_10MHz; GPIO_Init(GPIOA,&gpio_initStruct2);这些呢?即原本的6引脚是不配置了吗还是继续是开启的?
结论先说
第一次调用
GPIO_Init(GPIOA, &gpio_initStruct2);时,PA6 已经按AF_PP(复用推挽输出)模式成功配置。第二次你只是修改了
gpio_initStruct2变量里的成员,然后再调用一次GPIO_Init,这次配置只会影响你传进去的 引脚位(PA7)。之前 PA6 的配置不会被清掉,它会一直保持第一次配置的状态,直到你再用
GPIO_Init重新配置它,或者芯片复位。更形象的理解
你可以把寄存器想象成一个房间里很多开关(每个引脚占一组开关):
第一次配置 PA6 = 把 PA6 的那组开关拨好位置。
第二次配置 PA7 = 只动 PA7 的那组开关,PA6 的保持原状。
注意
虽然
gpio_initStruct2这个结构体变量被你覆盖了,但它只是一个传参数用的临时变量,跟硬件寄存器的状态没有直接绑定。
真正控制 GPIO 状态的是寄存器,不是这个结构体。所以变量值怎么改都不会“自动重置”之前的引脚,只有你再次调用GPIO_Init()并且包含那个引脚的GPIO_Pin时才会改变它。

2万+

被折叠的 条评论
为什么被折叠?



