嵌入式第四章作业
一、学习CH04示例程序,包括gpio.c和四个工程中的main.c
1、GPIO-ASM-STM32L431-20231129的main.s
功能概要:汇编编程调用GPIO构建控制小灯闪烁(利用printf输出提示信息)
代码思路:
(1)数据段与代码存储段的定义。
(2)开始编写main,在启动主循环前初始化定义外设模块、初始化用户外设模块、初始化串口、使能模块中断、开总中断。
(3)跳过启动部分,直接开始主循环部分,定义循环次数,设置灯状态标志mFlag为L,判断灯的状态标志,分别对mFlag为A和F地情况进行处理,同时管理灯的闪烁次数。
2、GPIO_BLUELIGHT-20230328的main.c
功能概要:按照这个c文件的文件名和注释,它应该说的是要求蓝灯亮来着,但是实际上它实现的功能是让红灯一直亮着
代码思路:
(1)gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF);初始化红灯,将红灯初始化为灭的
(2) gpio_set(LIGHT_RED,LIGHT_ON); 设置红灯使得红灯亮起来了
(3)使用for循环,使得程序一直处于执行状态,红灯一直亮
3、GPIO-Output-Component_STM32L431_20200928的main.c
功能概要:利用api实现蓝灯的亮灭循环
代码思路:
(1)定义主循环次数、灯亮灭标志、灯亮灭次数等变量
(3)gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_ON); //初始化蓝灯
(3)主循环部分:如灯状态标志mFlag为’L’,灯的闪烁次数+1并显示,改变灯状态及标志;如灯状态标志mFlag为’A’,改变灯状态及标志。
4、GPIO-Output-DirectAddress_STM32L431_20200928的main.c
功能概要:使用直接地址编程的方式实现蓝灯的亮灭循环
代码思路:
(1)声明b端口寄存器地址、复位寄存器地址等变量并赋值
(2)随后对GPIO进行初始化
(3)设置灯为亮
(4)进入循环亮灭状态
5、gpio.c文件
定义了gpio_get_port_pin、gpio_init、gpio_set、gpio_get、gpio_reverse、gpio_pull、gpio_enable_int等多个自定义函数
二、给出 gpio_set(LIGHT_RED,LIGHT_OFF); 语句中, LIGHT_RED和LIGHT_OFF的值是多少?贴出每一步的查找截图。
1、LIGHT_RED值
(1)在user.h文件中找到了LIGHT_RED由PTB_NUM|7定义
(2)在gpio.h中找到了PTB_NUM定义为1<<8。
(3)综上可知LIGHT_RED的值是263
2、LIGHT_OFF的值
在user.h中找到了LIGHT_OFF的值大小为0
三、用直接地址编程方式,实现红绿蓝三灯轮流闪烁
金葫芦的示例程序中有个让蓝灯亮灭的直接地址编程的例子。我根据那玩意改了改就成了红绿蓝三种颜色的灯交换亮了。
想要蓝灯亮,得看看书上表3-7,那里有蓝灯对应的针脚PTB9,还有绿蓝对应的针脚PTB8和PTB7,于是找到B端口对应的模式寄存器GPIOx_MODER,然后将这三个针脚对应的位都置为01,因为01在模式寄存器的配置中表示通用输出模式,就是让这三个对应三个灯的针脚输出信号。
那么要输出什么信号呢?因为针脚只能输出低电平和高电平,我们在书中的图3-4可以看到这三个灯实际上是发光二极管,从正负极来看要输出低电平才能点亮灯。那么就很明了了,我们只要让针脚输出低电平就可以点亮灯,输出高电平就可以熄灭灯。
那么要如何实现高低电平的输出状态改变呢?在端口还有一个寄存器GPIOx_BSRR,这个寄存器是用来控制引脚输出状态的。这个寄存器是32位的,高16位置和低16位都对应x端口的16个针脚。对于我们指定的B端口有16个针脚,寄存器的高16位对应相应的针脚时如果置为0则表示将此针脚置为低电平;寄存器的低16位对应的针脚如果置为1则表示将此针脚输出置为高电平。
所以想要实现红绿蓝三种灯的交替亮灭
只需要先 *gpio_brr|=(1<<7); 设置针脚输出为低电平,红灯“亮”;再 *gpio_bsrr|=(1<<7); 设置针脚输出为高电平,红灯灭。
然后就是绿灯 *gpio_brr|=(1<<8); 和 *gpio_bsrr|=(1<<8); 绿灯亮灭。
蓝灯gpio_brr|=(1<<9); 和 *gpio_bsrr|=(1<<9); 蓝灯亮灭。
对上面进行无限循环,一直亮灭交替。源代码如下:
#define GLOBLE_VAR
#include "includes.h" //包含总头文件
int main(void)
{
//(1)======启动部分(开头)==========================================
//(1.1)声明main函数使用的局部变量
uint32_t mMainLoopCount; //主循环使用的记录主循环次数变量
uint8_t mFlag; //主循环使用的临时变量
//(1.2)【不变】关总中断
DISABLE_INTERRUPTS;
//(1.3)给主函数使用的局部变量赋初值
mMainLoopCount = 0; //主循环使用的记录主循环次数变量
// mFlag='A'; //主循环使用的临时变量:蓝灯状态标志
//(1.4)给全局变量赋初值
//(1.5)用户外设模块初始化
// B口9脚(蓝灯,低电平点亮)
//(1.5.1)声明变量
volatile uint32_t* RCC_AHB2; //GPIO的B口时钟使能寄存器地址
volatile uint32_t* gpio_ptr; //GPIO的B口基地址
volatile uint32_t* gpio_mode; //引脚模式寄存器地址=口基地址
volatile uint32_t* gpio_bsrr; //置位/复位寄存器地址
volatile uint32_t* gpio_brr; //GPIO位复位寄存器
//(1.5.2)变量赋值
RCC_AHB2=(uint32_t*)0x4002104C; //GPIO的B口时钟使能寄存器地址
gpio_ptr=(uint32_t*)0x48000400; //GPIO的B口基地址
gpio_mode=gpio_ptr; //引脚模式寄存器地址=口基地址
gpio_bsrr=gpio_ptr+6; //置位/复位寄存器地址
gpio_brr=gpio_ptr+10; //GPIO位复位寄存器
//(1.5.3)GPIO初始化
//(1.5.3.1)使能相应GPIOB的时钟
*RCC_AHB2|=(1<<1); //GPIOB的B口时钟使能
//(1.5.3.1)定义B口9脚为输出引脚(令D19、D18=01)方法如下:
//这里使得B9变为了01,输出模式,亮蓝灯
*gpio_mode &= ~(3<<18); //0b11111111111100111111111111111111;
*gpio_mode |=(1<<18); //0b00000000000001000000000000000000;
//这里使得B8变为了01输出模式,绿灯亮
*gpio_mode &= ~(3<<16); //0b11111111111111001111111111111111;
*gpio_mode |=(1<<16); //0b00000000000000010000000000000000;
//这里使得B7变为了01输出模式,红灯亮
*gpio_mode &= ~(3<<14); //0b11111111111111110011111111111111;
*gpio_mode |=(1<<14); //0b00000000000000000100000000000000;
//(思考:为什么这样赋值?答案见本文件末尾注①)
//(1.6)使能模块中断
//(1.7)【不变】开总中断
ENABLE_INTERRUPTS;
printf("-----------------------------------------------------\r\n");
printf("金葫芦提示:直接地址方式进行GPIO输出\r\n");
printf(" 这个编程有点难以看懂,使用构件编程就简单多了,\r\n");
printf(" 但是构件制作要经过这一关,因此,我们把构件制作与\r\n");
printf(" 基于构件的编程分成不同过程。学习嵌入式系统,\r\n");
printf(" 以理解GPIO、UART、定时器、Flash、ADC、...\r\n");
printf(" 知识要素为出发点,学会正确运用构件进行应用编程,\r\n");
printf(" 理解和掌握2~3个简单构件的制作方法即可。\r\n");
printf("----------------------------------------------------\r\n");
//(1)======启动部分(结尾)==========================================
//(2)======主循环部分(开头)=========================================
for(;;) //for(;;)(开头)
{
//(2.1)主循环次数+1,并判断是否小于特定常数
mMainLoopCount++; //+1
if (mMainLoopCount<=6556677) continue; //如果小于特定常数,继续循环
//(2.2)主循环次数超过特定常数,灯状态进行切换(这样灯会闪烁)
mMainLoopCount=0; //清主循环次数
//红灯
//切换灯状态
*gpio_brr|=(1<<7); //设置灯“亮”
printf("红灯:亮\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
*gpio_bsrr|=(1<<7); //设置灯“暗”
printf("红灯:暗\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
//绿灯
*gpio_brr|=(1<<8); //设置灯“亮”
printf("绿灯:亮\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
*gpio_bsrr|=(1<<8); //设置灯“暗”
printf("绿灯:暗\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
//蓝灯
*gpio_brr|=(1<<9); //设置灯“亮”
printf("蓝灯:亮\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
*gpio_bsrr|=(1<<9); //设置灯“暗”
printf("蓝灯:暗\r\n"); //通过调试串口输出灯的状态
for(int i=0;i<10000000;i++)
{}
} //for(;;)结尾
//(2)======主循环部分(结尾)========================================
}