#include "fun.h"

void led_show(uint8_t led, uint8_t mode)
{
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    if(mode)  
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8<<(led-1), GPIO_PIN_RESET);
    else 
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8<<(led-1), GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

uint8_t led_flag;
uint8_t B1_data, B1_last=1, B2_data, B2_last=1, B3_data, B3_last=1, B4_data, B4_last=1;
float adc_value;
volatile uint16_t free;
uint8_t lcd_mode = 0 ;  //初始化为0
uint8_t  Rate;
uint8_t  Con_ut;
uint8_t  Rate_Max;
uint8_t  Rate_Min;
uint8_t  high = 100;
uint8_t  low  = 60;
uint8_t high_low =0;
uint8_t  flag_hl =0;
void key_pros()
{   
    B1_data = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0);
    B2_data = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1);
    B3_data = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2);
    B4_data = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); 
    
    // --- B1: 切换模式 ---
    if(!B1_data && B1_last)
    {
       if (lcd_mode == 1)  flag_hl = 0;
       if(++lcd_mode > 2) lcd_mode = 0; // 模式范围:0, 1, 2
    }
    
    // --- B2: 仅在 PARA 界面(2) 有效 ---
    if(!B2_data && B2_last) { 
       if(lcd_mode == 2)
       {
           high_low ^= 1;
       }
    }

    // --- B3: 修复这里 ---
    if(!B3_data && B3_last) {
    
        // 和 B2 一样在参数界面生效
        if(lcd_mode == 2) 
        {
            flag_hl ^= 1;
        }
    }


    if(!B4_data && B4_last) { }
    
    B1_last = B1_data;
    B2_last = B2_data;
    B3_last = B3_data;
    B4_last = B4_data; 
}

float adc_read(ADC_HandleTypeDef *hadc)
{
    HAL_ADC_Start(hadc);
    uint32_t adc_raw = HAL_ADC_GetValue(hadc);
    return 3.3f * adc_raw / 4096.0f;
}

char text[20];

void lcd_show()
{
    uint16_t temp = GPIOC->ODR;
    
    switch (lcd_mode)
    {
        case 0: 
            sprintf(text, "       HEART         ");
            LCD_DisplayStringLine(Line1, (uint8_t*)text);   
            sprintf(text, "      RATE:%.d         ", Rate);
            LCD_DisplayStringLine(Line3, (uint8_t*)text);
            sprintf(text, "       Con:%d         ", Con_ut);
            LCD_DisplayStringLine(Line4, (uint8_t*)text);
            break;
        
        case 1:
            sprintf(text, "       RECORD         ");
            LCD_DisplayStringLine(Line1, (uint8_t*)text);   
            sprintf(text, "       Max:%d         ", Rate_Max);
            LCD_DisplayStringLine(Line3, (uint8_t*)text);
            sprintf(text, "       Min:%d         ", Rate_Min);
            LCD_DisplayStringLine(Line4, (uint8_t*)text);
            break;
        
        case 2:
            sprintf(text, "        PARA         ");
            LCD_DisplayStringLine(Line1, (uint8_t*)text);   
            sprintf(text, "      High:%d         ", high);
            LCD_DisplayStringLine(Line3, (uint8_t*)text);
            sprintf(text, "       Low:%d         ", low);
            LCD_DisplayStringLine(Line4, (uint8_t*)text);
            break;
        
        default:
            lcd_mode = 0;
            break;
    }
    
    GPIOC->ODR = temp;
}

void data_proc(void)
{
    adc_value = adc_read(&hadc2);
    if(free<1000) Rate  =  30;
    else if (free>2000) Rate = 200;
    else Rate = 0.17* free -140;
    if(flag_hl)
   { if(!high_low)
        
    {
      if(adc_value <1) high = 60; 
      else if(adc_value>3) high=150;
      else high = 45*adc_value +15;        
        
        
    }
    
    
    
    else{
        
      if(adc_value <1) low = 60; 
      else if(adc_value>3) low=150;
      else low = 45*adc_value +15; 
        
        
        
        
        }
}
}
void main_pros()
{
    // 定义一个静态变量来计时
    static uint32_t lcd_time = 0; 

    // 1. 按键检测:每次循环都跑,保证反应快
    key_pros();      
    
    // 2. 数据处理:每次循环都跑
    data_proc();     
    
    // 3. LCD显示:改为每 100ms 刷新一次
    // 如果不加这个if,CPU 99%的时间都在画图,根本检测不到你按键松手的那一瞬间
    if(HAL_GetTick() - lcd_time > 100)
    {
        lcd_show();
        lcd_time = HAL_GetTick(); // 更新计时
    }
    
    for(int i=1; i<9; i++ ) 
        led_show(i, led_flag);
}

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM16)
    {
        uint32_t capture_value = TIM16->CCR1 +  1;
        TIM16->CNT = 0;
        free = 1000000 / capture_value;
    }
}


下面我罗列 出可能你会有  疑问的地方

stm32g431rbt6  蓝桥杯这个板子 我们首先要 打开PD2 号引脚  并且设置为高电平    在最后我们要 关闭 PD2号  并且 设置为低电平   

2 只要是中断或者 RTOS 任务里要用的全局变量,直接加上 volatile保平安 在上面的代码里面 我在中断那里面 加了 volatile 

3 下面我们讲解 flag hl^= 1;所以这个标志位会自己 找 0还是1 我只要在前面 定义uint8 t flag hl =0;  这正是编程里最“省事”的地方。你只需要做两步,剩下的计算机自己会搞定:

4 if(lcd mode ==1)flag hl = 0;-- 进门前先擦鞋(状态重置)这就好比你从“卧室”去“厨房”之前,必须把手里的脏东西扔掉,保证去下一个房间是干干净净的。现状:当 1cd_mode ==1时,你处于第2个界面(RECORD 界面)。
动作:你按下了 B1,意味着你要离开 RECORD 界面,前往下一个界面(PARA 界面,即lcd mode = 2 )。
目的: flag_h1 是你在 PARA 界面用来控制修改参数的标志位。
这行代码强制把 flag_h1 归零。

为什么?为了防止你上次在 PARA 界面操作了一半(比如 flag_hl 还是1),切走了又切回来时,界面处于一种奇怪的中间状态。
结论:这是为了保证每次进入 PARA 界面(界面2)时,状态都是默认的初始状态(0)。

5, 1cd_mode ==1 是第二个界面(也就是“RECORD”记录界面)。在C语言编程中,计数通常是从0开始的。我们来看一下 lcd_show函数里的对应关系:


 

6  硬件电路里 LED 是 “阳极接电源、阴极接 GPIO” 还是反过来?(如果是前者,就一定是 “GPIO 低电平点亮”;如果是后者,才是 “GPIO 高电平点亮”)

!0 结果是 1(把“没有”变成“有”)
• !1 结果是 0(把“有”变成“没有”)
• !5 结果也是 0(只要不是0,取反后都变成0)

! 来救场
加上 ! 之后,逻辑就顺了:
• 当你按下按键:
1. 硬件读到 0。
2. 代码执行 !0。
3. 结果变成 1 (True)。
4. 计算机理解为:是的,有事情发生了!
• 当你松开按键:
1. 硬件读到 1。
2. 代码执行 !1。
3. 结果变成 0 (False)。
4. 计算机理解为:没事发生。

8   初学者 一定对于 中断的 一些名词不理解  现在 我来讲解一下 

IC 是你要干什么(输入捕获),IT 是你怎么知道它干完了(通过中断通知)

CaptureCallback 是结果处理。

9.在 main 函数中调用 HAL库函数时,需要取地址(用&)原因:变星是结构体类型,函数需要指针类型参数
在回调函数中,参数已是指针,不需要再加&
简单记忆:
main函数:(取地址)&htim16
回调函数:htim直接用指针)

10 

配上 关系图 

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐