例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板

该系列博客调试过程搜寻大量网上经验,本人只是当作笔记在此记录,如有侵犯,请联系我,下架该文章,且本人能力有限,对代码理解难免出现纰漏以及错误的地方,敬请留言指正.
参考[1] 野火stm32 固件库例程

硬件平台: 蓝桥杯嵌入式开发板-stm32F103RBT6

开发环境: keilv5.27

注意事项:

[1]keil 在不断更新的过程中,将一些较老板卡的硬件数据压缩在器件支持包中.对于stm32F103RBT6在使用较高等级keil软件(5.24之后)时,需要安装器件支持包:MDKCM520.EXE,对于更高规格的R系列(实时控制领域)则需要安装:MDK Version 5 For ARM7 ARM9 Cortex-R V5.20.EXE芯片包.
[2]原本蓝桥杯大赛上的应用环境为keil4,在使用keil5作为开发环境建立工程时需要进行适当配置

知识点:

[1]在库文件中,针对每个外设,ST的工程师为了使得操作难度降低,通过使用stm32f10x.h 文件完成对寄存器的首次封装(其中通过使用数据结构类型-struct结构体内存分配的特点,),后编写的stm32f10x_gpio.c/.h文件中包含对外设的一些初始化/配置接口,再次封装.
[2]做到精确延时: 在不选用RTOS的情况下,可以使用cortex m3内核中自带外设 SysTick-系统滴答定时器
该外设属于内部外设,其中断优先级不由NVIC初始化,

例程目录

例程1 闪烁流水灯

例程2 按键中断

例程3 串口数据传输

例程1 闪烁流水灯

功能说明: 通过系统滴答定时器完成LED灯精确时间闪烁

工程文件树:

例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第1张图片
仅在HARDWARE文件组下根据不同用途,编写对应的BSP(各有一个源文件 bsp_xxx.c 用来书写函数的主体 和头文件bsp_xxx.h 进行函数声明 宏的定义 外部变量的引用 调用其他文件)
为此:
[1]对于LED灯,需要对GPIO进行配置
头文件:例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第2张图片
头文件中包含了对引脚的宏定义,并通过带参数的宏完成分支语句,注意:宏只能对一行的内容进行简单替换,在此通过续行符"\"连接内容. else 语句之后没有添加分号 为了在宏替换之后使用原先的分号,避免重复产生报错.

例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第3张图片
源文件:仅包含LED的GPIO的初始化函数 主要对GPIO初始化结构体成员进行配置 [1]引脚号 [2]引脚的工作方式 [3]输出速率
由于该扩展板的八路LED的引脚受控于74LS573芯片的LE,引脚,故须对LE引脚进行配置
通过电路图查阅
八路LED灯:LED1…8------>GPIOC-8…15
LE引脚: LE---->GPIOD-2
LE引脚在高电平时允许输出端及时受控于输入端,在低电平时进行引脚电平的锁存.

[2]系统滴答定时器
源文件:
例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第4张图片
调用了在core_cm3.h中定义的SysTick时钟初始化函数SysTick_Config()函数,对SysTick外设内部寄存器通过传入参数(累加计数时钟)进行配置,SystemCoreClock:在system_stm32f10x.h文件中声明的能够被外部文件引用的变量
定义static静态变量Decrement_count 保证该变量的作用域(仅在bsp_systick.c文件中使用)和生命周期.
由于Decrementing()函数并没有在bsp_systick.h文件中声明,故通过包含头文件的方式无法在其他C文件调用该函数,但在stm32f10x_it.c文件中需要执行SysTick中断函数(void SysTick_Handler(void)首先在启动文件中startup_stm32f10x_md.s中 进行weak类型声明和在中断向量表中 进行优先级的分配
) 完成时钟计数的递减操作,通过引用外部函数 extern void Decrementing(void)使函数能被正常调用

主函数
例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第5张图片
在主函数中对灯进行闪烁

例程2 按键中断

功能说明:

通过板载按键中断决定点亮某一路LED灯,该工程是在例程1 的基础上进行改动,且该例程说明只对添加部分–按键中断进行解释说明

工程文件树:

例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第6张图片
主要添加了针对按键功能建立的bsp_key.h和bsp_key.c
该例程演示4个按键中断 在此仅讲解其中按键2 作为模板
引脚关系:

按键 GPIO 引脚号 PortSource PinSource EXTI_Line EXTI_IRQn
KEY1 GPIOA Pin0 GPIO_PortSourceGPIOA GPIO_PinSource0 EXTI_Line0 EXTI0_IRQn
KEY2 GPIOA Pin8 GPIO_PortSourceGPIOA GPIO_PinSource8 EXTI_Line8 EXTI9_5_IRQn
KEY3 GPIOB Pin1 GPIO_PortSourceGPIOB GPIO_PinSource1 EXTI_Line1 EXTI1_IRQn
KEY4 GPIOB Pin2 GPIO_PortSourceGPIOB GPIO_PinSource2 EXTI_Line2 EXTI2_IRQn

[1]头文件 bsp_key.h 仅针对按键2

//普通初始化引脚所用参数 [1]引脚所属GPIO [2]引脚号 [3]GPIO时钟
#define KEY2_GPIO_Port				GPIOA
#define KEY2_GPIO_Pin				GPIO_Pin_8		
#define KEY2_GPIO_RCC				RCC_APB2Periph_GPIOA

//为之后调用函数GPIO_EXTILineConfig(PortSource,PinSource)  输入参数进行宏定义
#define KEY2_PortSource 			GPIO_PortSourceGPIOA
#define KEY2_PinSource				GPIO_PinSource8

//EXTI结构体成员外部中断线 NVIC 中断服务函数名(实质为地址) 进行宏定义
#define KEY2_EXTI_Line				EXTI_Line8
#define KEY2_EXTI_IRQn				EXTI9_5_IRQn
#define KEY2_EXTI_Handler			EXTI9_5_IRQHandler

[2]源文件 bsp_key.c

void KEY_EXTI_NVIC_Init(void)
{
 	EXTI_InitTypeDef EXTI_Init_Structure; //定义EXTI 外部中断初始化结构体
	NVIC_InitTypeDef NVIC_Init_Structure;//定义NVIC 嵌套中断向量 初始化结构体
	
	//对于Cortex-M3 系列对于NVIC仅使用部分 用四位决定中断优先级 
	//四位又分为 抢占优先级和子优先级最多支持16级中断
	
	//设定用1位来配置 抢占优先级 0/1 数字越小 优先级越高
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);	
	
	//配置EXTI初始化结构体成员
	EXTI_Init_Structure.EXTI_Line = KEY2_EXTI_Line ;
	EXTI_Init_Structure.EXTI_Mode = EXTI_Mode_Interrupt ;
	//在此选用 松开按键--> 作为触发事件
	EXTI_Init_Structure.EXTI_Trigger = EXTI_Trigger_Rising ;
	EXTI_Init_Structure.EXTI_LineCmd = ENABLE ;
 	EXTI_Init(&EXTI_Init_Structure);
	
	//配置NVIC初始化结构体成员
	NVIC_Init_Structure.NVIC_IRQChannel = KEY2_EXTI_IRQn ;  //中断通道 在stm32f10x.h 含有IRQn 枚举结构体
	NVIC_Init_Structure.NVIC_IRQChannelPreemptionPriority = 0 ;
	NVIC_Init_Structure.NVIC_IRQChannelSubPriority = 1 ;
	NVIC_Init_Structure.NVIC_IRQChannelCmd = ENABLE ;
	NVIC_Init(&NVIC_Init_Structure);
}

void KEY_GPIO_Init(void)
{
  	GPIO_InitTypeDef GPIO_Init_structure;
	
	RCC_APB2PeriphClockCmd(KEY1_GPIO_RCC,ENABLE);
	//类似于F4系列的 在使用GPIO外部中断时 使能SYSCFG时钟 F1系列使能AFIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

	GPIO_Init_structure.GPIO_Pin = KEY1_GPIO_Pin | KEY2_GPIO_Pin ;
	//由于需要检测外部电平 模式为:输入 空悬状态
	GPIO_Init_structure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
	GPIO_Init_structure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(KEY1_GPIO_Port,&GPIO_Init_structure);

	//类似F4 系列的SYSCFG_EXTILineConfig(PortSource,PinSource);函数
	//连接中断事件源到key引脚 每个EXTI通道分别连接到各个GPIO的引脚上
	GPIO_EXTILineConfig(KEY2_PortSource,KEY2_PinSource);
	
	KEY_EXTI_NVIC_Init();
}

在此引入<<野火-零死角玩转stm32 F1系列>>插图来更好理解 EXTI外部中断中断
例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第7张图片

通过该图:之前的使能APIO部分的时钟也能够理解其原因,每个GPIO的Pin0 都会连接到EXTI0通道,该函数GPIO_EXTILineConfig()就是用来配置该寄存器来决定中断事件源,必须先使能总体AFIO时钟 才能配置相应子寄存器.

在此使能AFIO时钟和中断事件源选择,对于外部按键中断的正常配置缺一不可.

[3]中断函数:stm32f10x_it.c

 void KEY2_EXTI_Handler(void)
{
	if(EXTI_GetITStatus(KEY2_EXTI_Line) == ENABLE)
	{
		EXTI_ClearITPendingBit(KEY2_EXTI_Line);
		LED3_ON;	
	 }
 }

注意点:由于在bsp_key.h中进行KEY2中断服务函数的重新宏定义

#define KEY2_EXTI_Handler EXTI9_5_IRQHandler
在stm32f10x_it.c文件中进行有关KEY2的中断服务函数主体的编写时,必须包含头文件,完成宏的替换,否则对keil而言,仅视为在stm32f10x_it.c文件中进行简单定义的函数,且该函数并没有被调用,而不视为针对某一事件的中断服务函数主体.(个人猜想:造成在发生中断时,PC指针继续指向在启动文件中的地址,造成死循环)

[4]主函数
例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板_第8张图片
主函数进行死循环,等待中断产生,跳转至中断服务函数.

例程3 串口数据传输

功能说明:

通过板载串口完成stm32和PC端的数据通信.由于个人PC常用外接口为USB口(为真正意义上的type-A标准接口),与stm32的串口在

工程文件树:

文件树
主要添加了针对功能建立的
引脚关系:

按键 GPIO 引脚号 PortSource PinSource EXTI_Line EXTI_IRQn
KEY1 GPIOA Pin0 GPIO_PortSourceGPIOA GPIO_PinSource0 EXTI_Line0 EXTI0_IRQn
KEY2 GPIOA Pin8 GPIO_PortSourceGPIOA GPIO_PinSource8 EXTI_Line8 EXTI9_5_IRQn

[1]头文件

[2]源文件

[3]中断函数:stm32f10x_it.c

[4]主函数

你可能感兴趣的:(例程迭代:更新至串口数据传输 基于蓝桥杯嵌入式开发板)