模块化处理

原因:将所有的代码都放入一个main中会显得繁冗所以进行模块化处理(推荐后续移植的模块统一都做这个处理,这样代码的易读性增加)

重点说明:

1.如果遇见了没有找到某文件的情况,请按上一章添加Driver文件夹一样将文件进行添加

2.本次的基础是以上一个文件进行开发的所以无需创建新工程

模块化处理步骤

  1. 右键选择工程右键进行创建头文件和源文件(timer.c和.h)

  2. 新建后将上一讲的GPIO初始化与定时器初始化放置到一起->在主函数中对这个文件进行声明(#include "timer.h"//定时器头文件)

    /*
     * timer.c
     *
     *  Created on: 2025年9月13日
     *      Author: leader
     */
    #include "debug.h"
    void Tim3_Init(u16 arr,u16 psc)//arr-自动重装载的值 psc-分频值
    {
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;//定义结构体
        NVIC_InitTypeDef NVIC_InitStructure;//定义结构体
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//打开TIM3的时钟(注意该时钟挂载的总线是哪一个APB1/APB2)TIM3-APB1
    
        TIM_TimeBaseInitStruct.TIM_ClockDivision=0;//时钟分割
        TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;//设置为向上计数
        TIM_TimeBaseInitStruct.TIM_Period=arr;//自动重装载值,5000为500ms
        TIM_TimeBaseInitStruct.TIM_Prescaler=psc;//设置分频值
    
        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);
        TIM_ITConfig(TIM3, TIM_IT_Update|TIM_IT_Trigger, ENABLE);
    
    
    
        NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;//需要记得使用拥有中断通道的时钟
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
    
        NVIC_Init(&NVIC_InitStructure);
    
        TIM_Cmd(TIM3, ENABLE);
    }
    // 定义舵机的PWM周期和占空比
    #define PWM_PERIOD 20000  // PWM周期为20ms (20000us)
    #define PWM_MIN 500       // 最小脉宽为0.5ms (500us)
    #define PWM_MAX 2500      // 最大脉宽为2.5ms (2500us)
    
    // 初始化TIM2以生成PWM信号
    void TIM2_PWM_Init(void)
    {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // 使能TIM2时钟
    
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        TIM_OCInitTypeDef TIM_OCInitStructure;
    
        // 配置TIM2的基本参数
        TIM_TimeBaseStructure.TIM_Period = PWM_PERIOD - 1;  // 设置自动重装值
        TIM_TimeBaseStructure.TIM_Prescaler = 96 - 1;       // 设置预分频器,96MHz/96 = 1MHz (1us)
        TIM_TimeBaseStructure.TIM_ClockDivision = 0;
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
    
        // 配置TIM2的PWM模式
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
        TIM_OCInitStructure.TIM_Pulse = PWM_MIN;  // 初始占空比为最小值
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    
        // 配置TIM2通道1
        TIM_OC1Init(TIM2, &TIM_OCInitStructure);  // 使用TIM2的通道1
        TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);  // 使能TIM2通道1的预装载寄存器
    
    
        TIM_ARRPreloadConfig(TIM2, ENABLE);               // 使能TIM2的自动重装寄存器预装载
    
        TIM_Cmd(TIM2, ENABLE);  // 使能TIM2
        //初始化GPIO以输出PWM信号-这里我将定时器2的初始化与它GPIO的初始化放在一起整合为1个函数
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  // 使能GPIOA时钟
    
            GPIO_InitTypeDef GPIO_InitStructure;
    
            // 配置PA0为复用推挽输出(TIM2通道1)
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    }
    void lock(unsigned char mode)//舵机的工作模式0-上锁 1-开锁
    {
    
        if(mode==0)//0度
        {
           TIM_SetCompare1(TIM2, 500);//设置占空比
        }else if(mode==1)
        {
           TIM_SetCompare1(TIM2, 1500);//设置占空比
    
        }
    }
    
    #ifndef DRIVER_TIMER_H_
    #define DRIVER_TIMER_H_
    
    void Tim3_Init(u16 arr,u16 psc);
    void TIM2_PWM_Init(void);
    void lock(unsigned char mode);
    #endif /* DRIVER_TIMER_H_ */
  3. 对应主函数中可以讲GPIO的初始化进行删除,同时将原来对定时器的设置变为使用封装的lock函数进行控制舵机的初始状态

    	int main(void)
    {
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
    	SystemCoreClockUpdate();//时钟配置
    	//USART_Printf_Init(115200);//串口1初始化
    	Delay_Init();//延时函数初始化
    	TIM2_PWM_Init();//定时器初始化
    	lock(1);//上锁
    	LCD_Init();//LCD初始化
    	LCD_Fill(0, 0, 127, 127, WHITE);//填充屏幕
    	LCD_ShowPicture(0, 0, 128, 128, gImage_1);//展示照片
    	unsigned char i=0;
    	while(i<128)
    	{
    	        LCD_DrawLine(i, 0, i, 10, RED);//绘制一条红色的随时间增长的红线(可以制作为进度条)
    	        i++;
    	        Delay_Ms(20);
    	}
    	/*进度条走完后,首页显示*/
    
    
    	LCD_ShowPicture(0, 0, 128, 128, gImage_2);
    	LCD_Show_Chinese(0, 0, "门锁状态上锁", RED, WHITE, 16, 0);
    	LCD_Show_Chinese(0,30,"输入密码",RED,WHITE,16,0);
    	while(1)
        {
    		
    	}
    }
  4. 封装LCD_Show_Chinese函数原来LCD_ShowChinese只能一个一个进行显示过于麻烦

    void LCD_Show_Chinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    {
        while(*s)
        {
    		LCD_ShowChinese(x,y,s,fc,bc,sizey,mode);
            x+=16;
            if(x>127){x=0; y+=16;}//换行
            s+=2;//由于我们使用的是汉字(2个字节)的字符串所以这个地方+=2
        }
    
    }

矩阵键盘的移植(注意:所有的GPIO都是挂载在APB2总线上)

接线说明:前4个引脚配置为Out_PP后4个引脚配置为IPU

R4-PD11 R3-PD9 R2-PE15 R1-PE13 C1-PE11 C2-PE9 C3-PE7 C4-PC5(这个是根据我买的矩阵键盘为例,如果大家是自己焊接的可以根据自己的需求进行DIY)

移植步骤

  1. 创建key.c和.h

  2. 将我们配置的LED的GPIO的代码进行移植并修改可以得到-key_init()按键初始化的书写

    void key_init()
    {
            //初始化GPIO
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);  // 使能GPIOD时钟
            GPIO_InitTypeDef GPIO_InitStructure;
            // 配置PA0为复用推挽输出(TIM2通道1)
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_9;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(GPIOD, &GPIO_InitStructure);
    
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  // 使能GPIOD时钟
    
            // 配置PA0为复用推挽输出(TIM2通道1)
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15|GPIO_Pin_13;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(GPIOE, &GPIO_InitStructure);
    
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);  // 使能GPIOD时钟
    
            // 配置PA0为复用推挽输出(TIM2通道1)
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_9|GPIO_Pin_7;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输出
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(GPIOE, &GPIO_InitStructure);
    
            RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);  // 使能GPIOD时钟
    
            // 配置PA0为复用推挽输出(TIM2通道1)
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
            GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
            GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
            GPIO_Init(GPIOC, &GPIO_InitStructure);
    }
  3. 按键读取函数的书写-key_read

    u8 key_read()
    {
        u8 temp=0;
        //R4
        GPIO_ResetBits(GPIOD, GPIO_Pin_11);GPIO_SetBits(GPIOD, GPIO_Pin_9);GPIO_SetBits(GPIOE, GPIO_Pin_15); GPIO_SetBits(GPIOE, GPIO_Pin_13);//设置首行为低电平然后列扫描(后续同上)
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11)==0)temp=4;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9)==0)temp=3;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_7)==0)temp=2;
        if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5)==0)temp=1;//C4
        //R3
        GPIO_SetBits(GPIOD, GPIO_Pin_11);GPIO_ResetBits(GPIOD, GPIO_Pin_9);GPIO_SetBits(GPIOE, GPIO_Pin_15); GPIO_SetBits(GPIOE, GPIO_Pin_13);
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11)==0)temp=8;//C1
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9)==0)temp=7;//C2
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_7)==0)temp=6;//C3
        if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5)==0)temp=5;//C4
        //R2
        GPIO_SetBits(GPIOD, GPIO_Pin_11);GPIO_SetBits(GPIOD, GPIO_Pin_9);GPIO_ResetBits(GPIOE, GPIO_Pin_15); GPIO_SetBits(GPIOE, GPIO_Pin_13);
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11)==0)temp=12;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9)==0)temp=11;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_7)==0)temp=10;
        if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5)==0)temp=9;
        //R1
        GPIO_SetBits(GPIOD, GPIO_Pin_11);GPIO_SetBits(GPIOD, GPIO_Pin_9);GPIO_SetBits(GPIOE, GPIO_Pin_15); GPIO_ResetBits(GPIOE, GPIO_Pin_13);
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_11)==0)temp=16;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_9)==0)temp=15;
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_7)==0)temp=14;
        if(GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5)==0)temp=13;
    
        return temp;
    }
  4. key.h文件的书写

    #ifndef DRIVER_KEY_H_
    #define DRIVER_KEY_H_
    
    void key_init();
    u8 key_read();
    #endif /* DRIVER_KEY_H_ */
  5. 在main文件中对这个key.h进行引用

  6. 主函数的书写

    
    	int main(void)
    {
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
    	SystemCoreClockUpdate();//时钟配置
    	//USART_Printf_Init(115200);//串口1初始化
    	Delay_Init();//延时函数初始化
    	TIM2_PWM_Init();//定时器初始化
    	GPIO_Pwm_Init();//GPIO初始化
    	TIM_SetCompare1(TIM2, 1500);//设置占空比
    	LCD_Init();//LCD初始化
    	LCD_Fill(0, 0, 127, 127, WHITE);
    	LCD_ShowPicture(0, 0, 128, 128, gImage_1);
    	unsigned char i=0;
    	while(i<128)
    	{
    	        LCD_DrawLine(i, 0, i, 10, RED);//绘制一条红色的随时间增长的红线(可以制作为进度条)
    	        i++;
    	        Delay_Ms(20);
    	}
    	/*进度条走完后,首页显示*/
    
    
    	LCD_ShowPicture(0, 0, 128, 128, gImage_2);
    	LCD_Show_Chinese(0, 0, "门锁状态:上锁", RED, WHITE, 16, 0);
    	LCD_Show_Chinese(0,30,"输入密码",RED,WHITE,16,0);
        key_init();
    	while(1)
        {
    		num = key_read();//获取当前按键的数字
            LCD_ShowIntNum(0, 0, num, 3, RED, WHITE, 16);
    	}
    }

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐