m_<:整个程序除去基本配置外由四部分组成,main.c、bsp_usart.c、bsp_led.c和stm32f4xx_it.c。其中,bsp_usart.c及.h负责外设USART寄存器的配置,使其能正常工作。bsp_led.c及.h负责外设LED寄存器的配置,使其能正常工作,main.c则是在USART配置完能正常操作后来实现USART怎么接收数据,然后通过控制LED的颜色判断接收到什么数据。在stm32f4xx_it.c中写入中断服务函数,这是本节重点。
1 main.c
#include "stm32f4xx.h"
#include "./led/bsp_led.h"
#include "./usart/bsp_usart.h" //可将全局变量引入
int main(void)
{
LED_GPIO_Config(); //配置GPIO口
USART_Config(); //配置USART
while (1)
{
if(Flag=='a') //Flag为全局变量,Flag为我们输入的字符(后面进一步说明)
{
Flag == '0'; //Flag复位
GPIO_ResetBits(GPIOF, GPIO_Pin_6); //若输入为'a',则红灯亮
}
if(Flag=='b')
{
Flag == '0';
GPIO_ResetBits(GPIOF, GPIO_Pin_7); //若输入为'b',则绿灯亮
}
}
}
2.1 bsp_led.h
#ifndef _BSP_LED_H //防止重定义
#define _BSP_LED_H
#include "stm32f4xx.h"
void LED_GPIO_Config(void); //声明配置函数
#endif
2.2 bsp_led.c
//bsp: board support package(板级支持包)
#include "bsp_led.h"
void LED_GPIO_Config(void)
{
//以下四个步骤适合所有外设的初始化
/* 第一步:开GPIO的时钟 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //GPIOF在AHB1总线上,另外注意,系统时钟已经自己设定了
/* 第二步:定义一个GPIO初始化结构体 */
GPIO_InitTypeDef GPIO_InitStruct;
/* 第三步:配置GPIO初始化结构体的成员 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //Pin6红色、Pin7绿色、Pin8蓝色
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStruct.GPIO_Speed = GPIO_Low_Speed; //2MHz
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉电阻
/* 第四步:调用GPIO初始化函数,把配置好的结构体的成员的参数写入寄存器 */
GPIO_Init(GPIOF, &GPIO_InitStruct); //将上述参数赋给GPIOF
GPIO_SetBits(GPIOF,GPIO_Pin_6); //输出置1,红灯灭
/* 配置绿灯GPIO引脚 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; //Pin7绿色
GPIO_Init(GPIOF, &GPIO_InitStruct);
GPIO_SetBits(GPIOF,GPIO_Pin_6); //输出置1,绿灯灭
}
3.1 bsp_usart.h
#ifndef __BSP_USART_H
#define __BSP_USART_H
#include "stm32f4xx.h"
extern char Flag; //声明全局变量Flag
void USART_Config(void); //配置USART
#endif
3.2 bsp_usart.c
#include "./usart/bsp_usart.h"
char Flag = '0'; //定义变量Flag,在头文件中声明为全局变量
/***************** 配置USART发送数据中断 **********************/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //定义一个中断结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择嵌套向量中断控制器组
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //设置USART为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢断优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC
}
void USART_Config(void)
{
/* 第一步:初始化GPIO */
GPIO_InitTypeDef GPIO_InitStructure; //TX与PA9相连,RX与PA10相连
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOA, ENABLE); //使能GPIO时钟
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
/* 配置Tx引脚为复用功能 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //选择复用模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //选择复用的发送引脚
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIO
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //选择复用的接收引脚
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIO
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //将PA9复用到USART1的TX上
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //将PA10复用到USART1的RX上
/* 第二步:配置串口初始化结构体 */
USART_InitTypeDef USART_InitStructure; //定义一个USART结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART时钟
/* 配置串口USART1模式 */
USART_InitStructure.USART_BaudRate = 115200; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位字长
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //选择输入和输出模式
USART_Init(USART1, &USART_InitStructure); //初始化USART
/* 第三步:配置串口的接收中断 */
NVIC_Configuration(); //嵌套向量中断控制器NVIC配置
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能串口接收中断,中断一直打开,接收到一个字节后,判断RXNE位为1,执行其中的中断服务函数
/* 第四步:使能串口 */
USART_Cmd(USART1, ENABLE);
}
4 stm32f4xx_it.c
#include "stm32f4xx_it.h"
#include "./usart/bsp_usart.h" //可将全局变量引入
void USART1_IRQHandler(void)
{
uint8_t ucTemp;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断TDR是否为非空,收到数据TXE位置1
{
ucTemp = USART_ReceiveData(USART1); //将字符转移到ucTemp中
USART_SendData(USART1, ucTemp); //将收到的字符发送出去
Flag = ucTemp; //将收到的字符转移到Flag中
}
}
说明1:我们需要一个变量Flag在中断服务函数与主函数之间传递信息,因为是两个不同的.c,故需要Flag为全局变量,定义方法:
1、在一个.c文件里面定义,可赋值
2、然后在该头文件里面用extern关键字申明
3、其他.c文件要使用的时,包含该头文件就可以了
4、头文件里面不能给变量赋值
说明2:对于发送数据,发送出去了再判断TDR是否为空;对于接收数据,接收之前先对RDR判断是否为不空。两者区别要注意。
说明3:本节只打开了数据接收中断,当判断有数据进来即刻执行中断服务函数,若是服务函数较大,可通过Flag传递信息,将执行任务分配到主函数中执行。下节将会分析另一种接口协议,CAN口。