小成的嵌入式系统作业4

1、学习CH04示例程序,包括gpio.c和4个工程中的main.c

(1)GPIO-ASM-STM32L431-20231129工程的main.c

这段代码用纯汇编语言控制一个蓝色发光二极管(LED)的闪烁。其主要分为几个部分:数据段定义、代码段定义、主函数、主循环。

①数据段定义(.data)

  • 定义数据存储data段开始,实际数据存储在RAM中;
  • 在RAM中定义了一系列字符串和变量,包括用于输出的字符串(hello_information、light_show1、light_show2和light_show3)、格式字符串(data_format)以及一些状态变量(mMainLoopCount、mFlag和mLightCount)。

②代码段定义(.text)

  • 定义代码存储text段开始,实际代码存储在Flash中;
  • 定义了主程序代码。

③主函数(main)

  • 初始化部分:这部分包括了一些初始化工作,如关总中断、初始化外设模块(蓝灯和串口UART),以及开总中断。
  • 显示初始化信息:使用printf函数输出hello_information定义的字符串。

④主循环(main_loop)

  • 主循环通过main_loop标签开始,其中包含了主循环次数的计数和控制LED的逻辑。
  • 在每次循环中,主循环次数会加1,并检查是否达到预设的循环次数。
  • 一旦达到设定值,则根据mFlag变量的值('L'或'A'),切换LED的状态(亮或暗):
  •     - 如果灯状态为'L',则灯的闪烁次数加1,将灯打开并输出灯的状态信息,然后将状态改为'A';
  •     - 如果灯状态为'A',则将灯关闭,并输出灯的状态信息,然后将状态改为'L'。

(2)GPIO-Output-Component_STM32L431_20200928工程的main.c

这段代码用构件方法控制一个蓝色发光二极管(LED)的闪烁。其主要分为主函数和主循环。

①主函数(main)

  • 初始化部分:进行了一系列初始化工作,包括初始化局部变量、关闭总中断、给局部变量赋初值、初始化外设模块(蓝灯)以及打印欢迎提示信息。

②主循环(main_loop)

  • 使用了一个无限循环for(;;),在该循环内部对主循环次数进行计数,并根据计数值执行LED的亮暗处理。
  • 当主循环次数未达到设定值时,继续循环。
  • 一旦达到设定值,则根据mFlag变量的值('L'或'A'),切换LED的状态(亮或暗):
  •     - 如果灯状态为'L',则灯的闪烁次数加1,将灯打开并输出灯的状态信息,然后将状态改为'A';
  •     - 如果灯状态为'A',则将灯关闭,并输出灯的状态信息,然后将状态改为'L'。

(3)GPIO-Output-DirectAddress_STM32L431_20200928工程的main.c

这段代码使用直接地址方式进行GPIO输出。其主要分为主函数和主循环。

①主函数(main)

  • 声明变量:定义了一些volatile修饰的uint32_t类型的变量,分别表示GPIOB的时钟使能寄存器地址、GPIOB的基地址、引脚模式寄存器地址、置位/复位寄存器地址以及GPIO位复位寄存器地址,并且对这些变量进行了相应的赋值。
  • GPIO初始化(直接针对寄存器进行)
  •    - 通过将相应的位设置为1来启用GPIOB的时钟,从而使能GPIOB口的时钟。
  •    - 通过对引脚模式寄存器的位操作,将B口9脚定义为输出引脚。

②主循环(main_loop)

  • 在主循环部分,使用了无限循环for(;;),循环体内部有以下操作:
  •    - 主循环次数递增,并检查是否超过特定值。
  •    - 如果超过特定值,通过对 GPIO的B口第9脚的置位/复位寄存器进行操作,来控制蓝灯的亮暗,并通过串口打印输出相应的信息。
  •    - 根据变量mFlag的状态,控制蓝灯的亮暗,并在每次操作后改变mFlag的值,以实现蓝灯的状态切换。

(4)GPIO-BlueLight_20230328工程的main.c

这段代码主要执行亮红灯操作,主要为一个主函数

主函数 (main)

  • 初始化一个名为 LIGHT_RED 的GPIO为输出模式,并设置初始状态为 LIGHT_OFF。
  • 通过 printf 输出一段文本,提示程序的运行状态。
  • 将 LIGHT_RED 的状态设置为 LIGHT_ON,使得连接到该GPIO的LED灯亮起。
  • (虽然项目名称叫BlueLight,但实际写的是红灯,所以红灯亮起)

(5)gpio.c

此代码段是一个针对STM32微控制器的GPIO(通用输入输出)驱动库,提供了对GPIO端口和引脚的配置和控制功能。

①核心功能

  • GPIO初始化 (gpio_init): 初始化指定的GPIO端口和引脚,设置为输入或输出模式,并定义初始状态(高电平或低电平)。
  • GPIO设置 (gpio_set): 设置指定GPIO端口和引脚的状态(高电平或低电平)。
  • GPIO读取 (gpio_get): 读取指定GPIO端口和引脚的当前状态。
  • GPIO状态反转 (gpio_reverse): 反转指定GPIO端口和引脚的当前状态。
  • GPIO拉配置 (gpio_pull): 配置指定GPIO端口和引脚的上拉或下拉电阻。
  • GPIO中断使能与禁用 (gpio_enable_int, gpio_disable_int): 开启或关闭指定GPIO端口和引脚的中断功能,并设置中断触发条件。
  • GPIO驱动能力设置 (gpio_drive_strength): 设置指定GPIO端口和引脚的输出驱动能力(低速、中速、高速、超高速)。
  • GPIO中断标志获取与清除 (gpio_get_int, gpio_clear_int, gpio_clear_allint): 获取、清除指定GPIO端口和引脚的中断标志,或清除所有端口的GPIO中断。

②辅助功能

  • 内部函数 gpio_get_port_pin: 解析传入的端口和引脚编号,用于内部调用,以确定操作的具体GPIO端口和引脚。

③数据结构

  • GPIO数组 (GPIO_ARR): 存储STM32各GPIO端口的基地址,方便通过端口号快速访问。
  • 中断号表 (table_irq_exti): 映射GPIO扩展中断的IRQ号,用于中断处理函数的配置。

2、给出gpio_set (LIGHT_RED,LIGHT_OFF);语句中LIGHT_RED和LIGHT_OFF的值是多少?贴出每一步的查找截图

打开user.h文件

可以得到LIGHT_OFF值为1,LIGHT_RED的值为(PTB_NUM|7),因此需要找到PTB_NUM的值

打开gpio.h文件

可以得到PTB_NUM的值为(1 << 8),因此LIGHT_RED的值为((1 << 8) | 7)=263

((1 << 8) | 7)运算

1 << 8: 将数字1左移8位。在二进制中,1表示为 00000001,左移8位后变为 0000000100000000,即256。

| 7: 将结果与7进行按位或操作。7在二进制中表示为 00000111。

因此结果为0000000100000111=263


3、用直接地址编程方式,实现红绿蓝三灯轮流闪烁

通过查看user.h文件,可以看到红绿蓝三种灯的引脚号分别为7、8、9

因此,可以在GPIO-Output-DirectAddress_STM32L431_20200928工程的基础上,通过改变引脚号来控制灯的变化

①首先需要更新修改输出引脚的定义

②编写循环,通过变化引脚从而控制灯的变化

代码如下:

#define GLOBLE_VAR
#include "includes.h"      //包含总头文件

//----------------------------------------------------------------------
//声明使用到的内部函数
//main.c使用的内部函数声明处

//----------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程见书稿)
int main(void)
{
    //(1)======启动部分(开头)==========================================
    printf("这里是小成的嵌入式作业:用直接地址编程方式,实现红绿蓝三灯轮流闪烁。\r\n");
    //(1.1)声明main函数使用的局部变量
    uint32_t mMainLoopCount;  //主循环使用的记录主循环次数变量
    uint8_t  mFlag;           //主循环使用的临时变量
    
    //(1.2)【不变】关总中断
    DISABLE_INTERRUPTS;
    
    //(1.3)给主函数使用的局部变量赋初值
    mMainLoopCount = 0;     //主循环使用的记录主循环次数变量
    mFlag = 'R';            //主循环使用的临时变量:初始设置为红灯
    
    //(1.5)用户外设模块初始化
    // 红灯连接到B口7脚,绿灯连接到B口8脚,蓝灯连接到B口9脚
    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位复位寄存器

    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位复位寄存器

    // 使能相应GPIOB的时钟
    *RCC_AHB2 |= (1<<1);                //GPIOB的B口时钟使能

    // 定义B口7, 8, 9脚为输出引脚
    *gpio_mode &= ~(3<<14);  // 清除B口7脚模式位
    *gpio_mode |= (1<<14);   // 设置B口7脚为输出
    *gpio_mode &= ~(3<<16);  // 清除B口8脚模式位
    *gpio_mode |= (1<<16);   // 设置B口8脚为输出
    *gpio_mode &= ~(3<<18);  // 清除B口9脚模式位
    *gpio_mode |= (1<<18);   // 设置B口9脚为输出

    //(1.7)【不变】开总中断
    ENABLE_INTERRUPTS;
    
    //(2)======主循环部分(开头)=========================================
    for(;;)     //for(;;)(开头)
    {
        mMainLoopCount++;                         //主循环次数+1
        if (mMainLoopCount <= 6556677) continue; //如果小于特定常数,继续循环
        mMainLoopCount = 0;                      //清主循环次数
        // 切换灯状态
        switch (mFlag) {
            case 'R':  // 红灯亮
                printf("红灯:亮\r\n");
                *gpio_brr |= (1<<7);  // 红灯亮
                *gpio_bsrr |= (1<<9);  // 蓝灯暗
                *gpio_bsrr |= (1<<8);  // 绿灯暗
                mFlag = 'G';  // 切换到绿灯
                break;
            case 'G':  // 绿灯亮
                printf("绿灯:亮\r\n");
                *gpio_brr |= (1<<8);  // 绿灯亮
                *gpio_bsrr |= (1<<7);  // 红灯暗
                *gpio_bsrr |= (1<<9);  // 蓝灯暗                
                mFlag = 'B';  // 切换到蓝灯
                break;
            case 'B':  // 蓝灯亮
                printf("蓝灯:亮\r\n");
                *gpio_brr |= (1<<9);  // 蓝灯亮
                *gpio_bsrr |= (1<<7);  // 红灯暗
                *gpio_bsrr |= (1<<8);  // 绿灯暗               
                mFlag = 'R';  // 切换回红灯
                break;
        }
    }     //for(;;)结尾
}

运行结果:

红绿蓝三灯轮流亮起 


4、用调用构件方式,实现红绿蓝的八种组合轮流闪烁

八种组合分别为:①灯亮;②绿灯亮;③灯亮;④红灯 + 绿灯亮(色);⑤红灯 + 蓝灯亮(色);⑥绿灯 + 蓝灯亮(色);⑦红灯 + 绿灯 + 蓝灯亮(色);⑧所有灯都不亮(

本题可以在GPIO-Output-Component_STM32L431_20200928工程的基础上修改实现

①首先需要更新修改模块初始化

②编写循环,通过控制红绿蓝三灯的亮暗实现三灯的八种组合轮流闪烁

代码为:

#define GLOBLE_VAR
#include "includes.h"      //包含总头文件

//----------------------------------------------------------------------
//声明使用到的内部函数
//main.c使用的内部函数声明处

//----------------------------------------------------------------------
//主函数,一般情况下可以认为程序从此开始运行(实际上有启动过程,参见书稿)
int main(void)
{
//(1)======启动部分(开头)==========================================
//(1.1)声明main函数使用的局部变量
	uint32_t mMainLoopCount;  //主循环次数变量
	uint8_t  mFlag;           //灯的状态标志
	uint32_t mLightCount;     //灯的状态切换次数

//(1.2)【不变】关总中断
	DISABLE_INTERRUPTS;

//(1.3)给主函数使用的局部变量赋初值
    mMainLoopCount=0;    //主循环次数变量
	mFlag=0;           //灯的状态标志
	mLightCount=0;       //灯的闪烁次数

//(1.4)给全局变量赋初值
   
//(1.5)用户外设模块初始化
	gpio_init(LIGHT_BLUE, GPIO_OUTPUT, LIGHT_OFF);  //初始化蓝灯
    gpio_init(LIGHT_RED, GPIO_OUTPUT, LIGHT_OFF);   //初始化红灯
    gpio_init(LIGHT_GREEN, GPIO_OUTPUT, LIGHT_OFF); //初始化绿灯

//(1.6)使能模块中断
    
   
//(1.7)【不变】开总中断
	ENABLE_INTERRUPTS;
	
	printf("这里是小成的嵌入式作业:用调用构件方式,实现红绿蓝的八种组合轮流闪烁。\n");  
    //asm ("bl .");
    
        
//(1)======启动部分(结尾)==========================================

//(2)======主循环部分(开头)========================================
	for(;;)   //for(;;)(开头)
    {
        mMainLoopCount++;
        if (mMainLoopCount <= 12888999) continue;
        mMainLoopCount = 0;

        // 切换灯的状态
        switch (mFlag) {
            case 0:
                gpio_set(LIGHT_RED, LIGHT_ON);
                gpio_set(LIGHT_GREEN, LIGHT_OFF);
                gpio_set(LIGHT_BLUE, LIGHT_OFF);
                printf("当前颜色为:红\n");  // 输出当前状态
                break;
            case 1:
                gpio_set(LIGHT_RED, LIGHT_OFF);
                gpio_set(LIGHT_GREEN, LIGHT_ON);
                gpio_set(LIGHT_BLUE, LIGHT_OFF);
                printf("当前颜色为:绿\n");  // 输出当前状态
                break;
            case 2:
                gpio_set(LIGHT_RED, LIGHT_OFF);
                gpio_set(LIGHT_GREEN, LIGHT_OFF);
                gpio_set(LIGHT_BLUE, LIGHT_ON);
                printf("当前颜色为:蓝\n");  // 输出当前状态
                break;
            case 3:
                gpio_set(LIGHT_RED, LIGHT_ON);
                gpio_set(LIGHT_GREEN, LIGHT_ON);
                gpio_set(LIGHT_BLUE, LIGHT_OFF);
                printf("当前颜色为:黄\n");  // 输出当前状态
                break;
            case 4:
                gpio_set(LIGHT_RED, LIGHT_ON);
                gpio_set(LIGHT_GREEN, LIGHT_OFF);
                gpio_set(LIGHT_BLUE, LIGHT_ON);
                printf("当前颜色为:紫\n");  // 输出当前状态
                break;
            case 5:
                gpio_set(LIGHT_RED, LIGHT_OFF);
                gpio_set(LIGHT_GREEN, LIGHT_ON);
                gpio_set(LIGHT_BLUE, LIGHT_ON);
                printf("当前颜色为:青\n");  // 输出当前状态
                break;
            case 6:
                gpio_set(LIGHT_RED, LIGHT_ON);
                gpio_set(LIGHT_GREEN, LIGHT_ON);
                gpio_set(LIGHT_BLUE, LIGHT_ON);
                printf("当前颜色为:白\n");  // 输出当前状态
                break;
            case 7:
                gpio_set(LIGHT_RED, LIGHT_OFF);
                gpio_set(LIGHT_GREEN, LIGHT_OFF);
                gpio_set(LIGHT_BLUE, LIGHT_OFF);
                printf("当前颜色为:暗\n");  // 输出当前状态
                break;
        }
        mFlag = (mFlag + 1) % 8;  // 更新状态标志,循环通过八种状态
	}  //for(;;)结尾
}   //main函数(结尾)

运行结果:

红绿蓝的八种组合轮流闪烁,依次为(红、绿、蓝、黄、紫、青、白、暗)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值