- 开发板原理图
本次实验使用的串口是USART1串口,而它的读写管脚挂接在GPIOA的9、10脚上。如下图
2. 准备工作(此次实验根据上一次的PWM的程序进行改造得来)
串口的使用对于单片机来讲是公用的,也就是说我们这次所书写的程序可以用于以后的程序来使用,
所以可以将该实验的程序代码放在一个公共文件夹我命名为Public(我看的视频教程中的文件夹就是这样,哈哈)中,
和位带程序和Systick程序一起。
操作过程复述:
串口配置函数:
(1) 建立Usart.c和Usart.h文件,存放于Public文件,添加到工程里。
(2) 查找rcc.h文件,发现USART1串口挂接在APB2总线上,于是先使能APB2总线。
(3) 既然USART1的读写口都挂接在GPIOA上,就需要将GPIOA使能,
为了增强程序的可移植性,将GPIOA宏定义为USART1_GPIO,相应的管脚也宏定义
使能USART_GPIO
下面配置需要使用的GPIOA的管脚。
基本步骤,定义一个结构体后配置好相应的参数。
两个管脚的模式为什么要这样设定我还不是很懂。
接下来是串口的配置了。
(4) 类似于GPIO的初始化操作一样。
结构体有6个参数
USART_BaudRate 比特率
USART_WordLength 数据字节长度
USART_StopBits 停止位长度
USART_Parity 奇偶校验选项
USART_HardwareFlowControl 硬件流控制选项
USART_Mode 串口模式选项
之后是使能串口
下一步是清除串口中断的标志位,可以不加,加上过后可以提高程序的稳定性。
USART_FLAG_TC表明串口中断完成。
下面是使能串口中断(让串口可以接收中断)
USART_IT_RXNE:接收中断
(5)最后设置NVIC相关操作。
所有关于串口中断的启动程序就写完了,下面就是关于中断服务函数的书写。
中断服务函数:
实现的功能是PC向单片机发送数据,然后单片机将数据回显给PC机。
首先,需要有一个可以存储我们PC机发送数据的一个临时变量,首先让变量等于我们的PC机发送的数据,然后再将该变量回发给我们的PC机即可,
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
这句话的意思是,当我们的串口发送完成的时候,函数返回值是1,而SET在库函数中的值也是1,此时就会使得while内的条件为0,即为假,while循环便会退出,完成一次中断的服务。
而没有完成发送的时候,函数的返回值是0,while内的条件一直是1,循环就不会退出,使得我们可以继续发送数据,直到我们的数据发送完成。
下面是代码部分
Usart.h
#ifndef _USART_H
#define _USART_H
#include "system.h"
void USART1_Init(u32 bound);
#define USART1_TX_PIN GPIO_Pin_9
#define USART1_RX_PIN GPIO_Pin_10
#define USART1_GPIO GPIOA
#endif
Usart.c
#include "Usart.h"
//时间:2020-1-14
//制作者:SaBo
//适用:STM32F103ZET6 (普中科技 PZ6800L)
//串口的初始化函数,GPIO、NVIC、USART初始化的程序书写地方
void USART1_Init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//GPIOA_PIN_9是输出数据的管脚,设置为复用输出模式
//TX
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //设置推挽输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(USART1_GPIO,&GPIO_InitStructure); /* 初始化GPIO */
//GPIOA_PIN_10是数据的接收管脚,设置为浮空输入模式
//RX
GPIO_InitStructure.GPIO_Pin=USART1_RX_PIN; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //设置推挽输出模式
GPIO_Init(USART1_GPIO,&GPIO_InitStructure); /* 初始化GPIO */
//串口配置
USART_InitStructure.USART_BaudRate=bound; //波特率由参数设置
USART_InitStructure.USART_WordLength=USART_WordLength_8b; //八个字节长度
USART_InitStructure.USART_StopBits=USART_StopBits_1; //一个停止位
USART_InitStructure.USART_Parity=USART_Parity_No; //不使用奇偶校验
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//没有硬件流的控制
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx; //既要读又要写,通过或运算符连接
USART_Init(USART1,&USART_InitStructure);
//使能串口
USART_Cmd(USART1,ENABLE);
//清除标志位
USART_ClearFlag(USART1,USART_FLAG_TC);//发送完成的标识清除,用于增加程序的健壮性
//使能中断
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
//设置优先级
NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//中断服务函数
void USART1_IRQHandler()
{
u8 r;
//不等于0,就是接收到中断,执行服务函数
if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)
{
//按字节接收
//接收数据函数
r=USART_ReceiveData(USART1);
USART_SendData(USART1,r); //发送数据函数
//发送完成的标识
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//发送完成的话,这个标识会被置为1,当返回值是1的时候,就会退出这个while循环表明我们的数据发送完成。
}
}
main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "pwm.h"
#include "Usart.h"
//时间:2020-1-14
//制作者:SaBo
//适用:STM32F103ZET6 (普中科技 PZ6800L)
/*********************************************
程序写好后,下载到开发板上,打开我们的串口调试助手,
设置波特率为9600,数据位8位,停止位1位
发送什么就会在串口调试助手上回显出来。
led1的闪烁表明我们的程序是否正常在进行。(检测作用)
*********************************************/
//---------------------------------------
//名称:主函数
//适用:STM32F103ZET6 (普中科技 PZ6800L)
//日期:2020-1-14
//---------------------------------------
int main()
{
u8 i;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
LED_Init();
USART1_Init(9600);
while(1)
{
i++;
if(i%20 == 0)
led1=!led1;
delay_ms(10);
}
}