- 学习CH04示例程序,包括gpio.c和4个工程中的main.c.
-
给出 gpio_set(LIGHT_ RED LIGHT_ OFF); 语句中,LIGHT_RED和LIGHT_ OFF的值是多少?贴出每一 步的查找截图。
LIGHT_RED 和 LIGHT_ OFF 在 user.h中定义
//指示灯端口及引脚定义
#define LIGHT_RED (PTB_NUM|7) //红灯,(GEC_56)
//灯状态宏定义(灯亮、灯暗对应的物理电平由硬件接法决定)
#define LIGHT_ON 0 //灯亮
#define LIGHT_OFF 1 //灯暗
则 LIGHT_RED = (PTB_NUM|7)
PTB_NUM 为端口号地址偏移值 ,在gpio.h头文件中有定义
PTB_NUM = 0b10000 0000 (1<<8)
则LIGHT_RED的值 = PTB_NUM|7 = 0b10000 0111
LIGHT_OFF 对应值为 1
-
执行
gpio_set(LIGHT_ RED LIGHT_ OFF);的步骤调用在 03_MCU\MCU_drivers目录下的
gpio.c中的gpio_set()函数LIGHT_ RED 对应参数 port_pin = (PTB_NUM|7)
LIGHT_ OFF 对应参数 state = 1
之后执行
gpio_get_port_pin(port_pin,&port,&pin);-
调用
gpio_get_port_pin()函数根据带入参数port_pin,解析出端口与引脚分别赋给port,pin
则对应将LIGHT_ RED = 0b10000 0111 作为 port_pin 参数传入,并解析
那么
*port = (port_pin>>8);再右移8位 得到 端口号 port = 1*pin = port_pin;得到 引脚号 pin = 7
再返回到
gpio_set()函数中执行//根据port,给局部变量gpio_ptr赋值(GPIO基地址) if(7 == port) //GPIOH gpio_ptr = GPIO_ARR[port-2]; else gpio_ptr = GPIO_ARR[port]; //根据state,设置对应引脚状态 if(1 == state) //高电平(该引脚对应置位寄存器置1) gpio_ptr->BSRR = (uint32_t)(1u<<pin); else //低电平(该引脚对应重置寄存器置1) gpio_ptr->BRR = (uint32_t)(1u<<pin);计算 GPIO基地址 gpio_ptr = GPIO_ARR[1];
则 *gpio_ptr = (GPIO_TypeDef )GPIOB_BASE
GPIOB_BASE = AHB2PERIPH_BASE + 0x0400UL
AHB2PERIPH_BASE = PERIPH_BASE + 0x08000000UL
PERIPH_BASE = 0x40000000UL
对应gpio_ptr = 0x40000000UL + 0x08000000UL + 0x0400UL = 0x480000400UL
GPIO B口基地址值为 0x480000400UL
由于 state = 1,则 引脚状态值为 高电平
if(1 == state) //高电平(该引脚对应置位寄存器置1) gpio_ptr->BSRR = (uint32_t)(1u<<pin);将
128(即1u << 7的结果)作为参数写入gpio_ptr->BSRR寄存器,这将使与第 7 位相对应的 GPIO 引脚置为高电平(即设置为1)完成
gpio_set()函数 引脚状态 的设定 -
-
用直接地址编程方式,实现红绿蓝三灯轮流闪烁
在GPIO-Output-DirectAddress_STM32L431_20200928工程的main.c文件的基础上进行修改实现
- 添加了红灯和绿灯的 GPIO 配置,设置它们为输出模式-01
- 修改了主循环部分,在每次循环中,根据当前的灯状态标志
mFlag来控制哪盏灯亮,并在下次循环前关闭所有灯 - 通过
switch语句控制灯的状态标志切换,以及控制哪盏灯亮 - 添加了延时函数,使得每次灯亮1s后才会切换,方便观察结果
#define GLOBLE_VAR #include "includes.h" //包含总头文件 //---------------------------------------------------------------------- //声明使用到的内部函数 //main.c使用的内部函数声明处 void Delay_ms(uint16_t u16ms); //---------------------------------------------------------------------- //主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程见书稿) int main(void) { //(1)======启动部分(开头)========================================== //(1.1)声明main函数使用的局部变量 uint32_t mMainLoopCount; //主循环使用的记录主循环次数变量 uint8_t mFlag; //主循环使用的临时变量 //(1.2)【不变】关总中断 DISABLE_INTERRUPTS; //(1.3)给主函数使用的局部变量赋初值 mMainLoopCount = 0; //主循环使用的记录主循环次数变量 mFlag='R'; //主循环使用的临时变量:当前亮的灯('R':红灯,'G':绿灯,'B':蓝灯) //(1.4)给全局变量赋初值 //(1.5)用户外设模块初始化 user. // B口7脚(红灯,低电平点亮) // B口8脚(绿灯,低电平点亮) // 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)设置 B7、B8、B9 引脚为输出引脚-01 // 定义B口7脚为输出引脚(令D15、D14=01) *gpio_mode &= ~(3<<14); //15,14位 置0 *gpio_mode |=(1<<14); //14位置1 // 定义B口8脚为输出引脚(令D17、D16=01) *gpio_mode &= ~(3<<16); //16,17位 置0 *gpio_mode |=(1<<16); //16位置1 // 定义B口9脚为输出引脚(令D19、D18=01) *gpio_mode &= ~(3<<18); *gpio_mode |=(1<<18); //(1.6)使能模块中断 //(1.7)【不变】开总中断 ENABLE_INTERRUPTS; //(2)======主循环部分(开头)========================================= for(;;) //for(;;)(开头) { //(2.1)主循环次数+1,并判断是否小于特定常数 mMainLoopCount++; //+1 if (mMainLoopCount<=6556677) continue; //如果小于特定常数,继续循环 //(2.2)主循环次数超过特定常数,灯状态进行切换(这样灯会闪烁) mMainLoopCount=0; //清主循环次数 // 根据当前灯的状态标志切换灯状态 switch (mFlag) { case 'R': // 红灯 *gpio_brr |= (1 << 7); // 点亮红灯 printf("红灯:亮\r\n"); mFlag = 'G'; // 切换到绿灯 break; case 'G': // 绿灯 *gpio_brr |= (1 << 8); // 点亮绿灯 printf("绿灯:亮\r\n"); mFlag = 'B'; // 切换到蓝灯 break; case 'B': // 蓝灯 *gpio_brr |= (1 << 9); // 点亮蓝灯 printf("蓝灯:亮\r\n"); mFlag = 'R'; // 切换到红灯 break; } // 在下一次循环开始前,关闭所有灯,从而保证下一次只有一种颜色的灯亮 *gpio_bsrr |= ((1 << 7) | (1 << 8) | (1 << 9)); // 关闭所有灯 //延迟1s Delay_ms(1000); } //(2)======主循环部分(结尾)======================================== } //函数名称:Delay_ms //函数返回:无 //参数说明:近似毫秒 //功能概要:延时 - 毫秒级 //====================================================================== void Delay_ms(uint16_t u16ms) { for(volatile uint32_t i = 0; i < 8000*u16ms; i++) __asm("NOP"); }编译后,进行串口更新的结果:
-
用调用构件方式,实现红绿蓝的八种组合轮流闪烁
在GPIO-Output-Component_STM32L431_20200928工程的main.c文件基础上进行修改,参照CH01中的示例进行实现
设置红绿蓝的八种组合一个循环40s,每5s更换
按 暗-红-绿-黄-蓝-紫-青-白顺序亮灯
#define GLOBLE_VAR #include "includes.h" //包含总头文件 //---------------------------------------------------------------------- //声明使用到的内部函数 //main.c使用的内部函数声明处 void Delay_ms(uint16_t u16ms); //---------------------------------------------------------------------- //主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程,参见书稿) int main(void) { //(1)======启动部分(开头)========================================== //(1.1)声明main函数使用的局部变量 uint32_t mCount; //延时的次数 //(1.2)【不变】关总中断 DISABLE_INTERRUPTS; //(1.3)给主函数使用的局部变量赋初值 mCount=0;//记次数 //(1.4)给全局变量赋初值 //(1.5)用户外设模块初始化 gpio_init(LIGHT_RED,GPIO_OUTPUT,LIGHT_OFF); //初始化红灯 gpio_init(LIGHT_GREEN,GPIO_OUTPUT,LIGHT_OFF); //初始化绿灯 gpio_init(LIGHT_BLUE,GPIO_OUTPUT,LIGHT_OFF); //初始化蓝灯 uart_init(UART_User,115200); //初始化串口模块 //(1.6)使能模块中断 uart_enable_re_int(UART_User); //(1.7)【不变】开总中断 ENABLE_INTERRUPTS; //(1)======启动部分(结尾)========================================== //(2)======主循环部分(开头)======================================== for(;;) //for(;;)(开头) { //延时1秒 Delay_ms(1000); if(mCount==0) { printf("指示灯颜色为【暗色】\n"); } mCount++;//记录秒数 //八种组合一次循环时间为40s,当秒数40秒时,重新开始计数 //避免一直累加 if (mCount >= 40) { mCount=0; } //实现红绿蓝的八种组合轮流闪烁,每5s一切换 if(mCount%5==0) { gpio_reverse(LIGHT_RED); printf(" LIGHT_RED:reverse--\n"); //串口输出灯的状态 if(mCount/5==1) { printf("指示灯颜色为【红色】\n"); } else if(mCount/5==3) { printf("指示灯颜色为【黄色】\n"); } else if(mCount/5==5) { printf("指示灯颜色为【紫色】\n"); } else if(mCount/5==7) { printf("指示灯颜色为【白色】\n"); printf("------------------------------------------\n"); } } if (mCount%10==0) //判断灯的状态标志 { gpio_reverse(LIGHT_GREEN); printf(" LIGHT_GREEN:reverse--\n"); //串口输出灯的状态 if(mCount/10==1) { printf("指示灯颜色为【绿色】\n"); } else if(mCount/10==3) { printf("指示灯颜色为【青色】\n"); } } if (mCount%20==0) //判断灯的状态标志 { gpio_reverse(LIGHT_BLUE); printf(" LIGHT_BLUE:reverse--\n"); //串口输出灯的状态 if(mCount/20==1) { printf("指示灯颜色为【蓝色】\n"); } } } //for(;;)结尾 //(2)======主循环部分(结尾)======================================== } //main函数(结尾) //======以下为主函数调用的子函数=========================================== //====================================================================== //函数名称:Delay_ms //函数返回:无 //参数说明:近似毫秒 //功能概要:延时 - 毫秒级 //====================================================================== void Delay_ms(uint16_t u16ms) { for(volatile uint32_t i = 0; i < 8000*u16ms; i++) __asm("NOP"); }编译后,进行串口更新的结果: