蓝桥杯嵌入式

蓝桥杯嵌入式代码

更新日记
4.5 添加读取adc函数 给出pwm配置建议及快速操作 给出定时器计算公式
4.7 更新&&改正eeprom错误



一、LED模块

led

SN74HC573为锁存器芯片
LE为锁存使能 低电平锁存输出状态不变
输出有效且未锁存的状态 输入等于输出

根据电路来看输出等于输入为低电平的时候led灯亮

void led_disp(uint8_t ledmark)
{
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//解除锁存状态
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);//熄灭led
	HAL_GPIO_WritePin(GPIOC,ledmark<<8,GPIO_PIN_RESET);//GPIO为16位 高八位对应led 左移八位操作led
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);//锁存
}

二、按键

button

作者电路分析不是很好 就不分析了学会再回来补上
江科大yyds
按键未按下时IO口读到高电平
按键按下IO口读取到低电平

1.阻塞式按键

uint8_t Key_GetNum(void)
{
	uint8_t KeyNum = 0;
	if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0)//只给出一个按键其余自己写就是换个引脚
	{
		HAL_Delay(20);
		while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0);
		HAL_Delay(20);
		KeyNum = 1;
	}
	return KeyNum;
}

2.非阻塞式按键(单击,双击,长按)基于江科大非阻塞式按键

按键判断优先级 长按>双击>单击
看着长分为四部分 传递函数 状态函数 判断函数 计时函数
说一下最长的判断函数分为两小部分 每二十秒读取状态 判断是否长按 然后再判断是否双击

key.c

#include "main.h"
#include "gpio.h"
#include "key.h"

uint8_t KeyNum,is_first,is_long_press;
uint16_t double_click,press_time,long_press_time=50;

uint8_t Key_GetNum(void)//向外界传递按键值
{
	uint8_t temp;
	if(KeyNum)
	{
	temp=KeyNum;
	KeyNum=0;
	return temp;
	}
	return 0;
}

uint8_t Key_GetState(void)//读取按键状态
{
	if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
	{
	return 4;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==0)
	{
	return 1;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==0)
	{
	return 2;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==0)
	{
	return 3;
	}return 0;
}
	
void Key_Kick(void)
{
	static uint8_t i;//切记static一定要加
	static uint8_t past,now;
	i++;
	if (i >= 20) {
        i = 0;
        past = now;
        now = Key_GetState();

        // 长按检测逻辑
        if (past == now && now != 0) {
            press_time++;
            if (press_time >= long_press_time  ) {
                KeyNum = now + 5; // 长按事件编码(1→6, 2→7, 3→8, 4→9)
                is_long_press = 1;
                press_time = 0;
            }
        } else {
            press_time = 0;
        }
		//长按松手或短按
        if (past != 0 && now == 0) {
            //如果不是松手
			if(!is_long_press){
                if (is_first) {
                    is_first = 0;
                    double_click = 0;
                    KeyNum = 5; // 双击事件
                } else {
                    KeyNum = past; // 短按事件
                    is_first = 1;
                    double_click = 0;
                }
            }
            //清除标志位防止程序无法进入短按
			is_long_press=0;
        } 
    }

}

void Key_HandleDoubleClickTimer(void)//此函数用于计算双击间隔时间
{
    // 双击计时
    if (is_first)
    {
        double_click++;
        if (double_click >= 300)//超过300ms则不是双击
        {
            is_first = 0;
            double_click = 0;
        }
    }
}


三 、LCD

请添加图片描述

LCD引脚和LED引脚有所重复 更改LCD前记得锁存
直接移植官方文件即可

 char text[20];
 sprintf(text,"  KEY=%d  ",Keynum);//将KEY=%d打印到text数组中 
 LCD_DisplayStringLine(Line1,(uint8_t *)text);
 //在第二行显示text	
 //Line0才是真正意义上的第一行

四、定时器

定时器详解
我直接给公式和代码了

stm32cubemx操作:使能,开中断,配置参数

1、基本计时功能

T=(psc+1)*(arr+1)/80000000 单位s

HAL_TIM_Base_Start_IT(&htim6);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	//代码
	Key_Kick();	
	Key_HandleDoubleClickTimer();
}

2、ADC

//一次启动得到一次数据 持续捕获需放入循环
  //HAL_ADC_Start(&hadc1);
  //HAL_ADC_Start(&hadc2);  
  //adc2=HAL_ADC_GetValue(&hadc1)*3.3/4095;
  //adc1=HAL_ADC_GetValue(&hadc2)*3.3/4095;
float adc_read(ADC_HandleTypeDef *hadc)
{
	HAL_ADC_Start(hadc);
	uint32_t Value=HAL_ADC_GetValue(hadc);
	return 3.3f*Value/4096;
}

3、PWM

建议PSC为799 ARR为99
这时频率为1khz
PSC缩小为399 频率为2khz
PSC缩小为199 频率为4khz以此类推
CCR为多少占空比为多少

// 启动PWM
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
// 设置占空比(50% duty)
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, htim2.Instance->ARR / 2);
__HAL_TIM_SET_PRESCALER(&htim2,800);  
 快速设置
 TIMx->CNT=
 TIMx->ARRx= 通道几就是arr几
 TIMx->PSC=
  //f=80000000/(psc+1)*(arr+1)
  //duty=ccr/arr+1

4、输入捕获

// 启动输入捕获
HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);

// 输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim==(&htim3))
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
		{
		com1=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_1);
		com2=HAL_TIM_ReadCapturedValue(&htim3,TIM_CHANNEL_2);
		__HAL_TIM_SetCounter(htim,0);
		
			
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
			HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
		}
		
		
	}

}

while(1)
{
//计算函数放在主循环
		fre=80000000/80/com1;
		duty=(com2/com1)*100;
}

五、串口

HAL_UART_Receive_IT(&huart1,&rxdat,1);

int fputc(int ch, FILE *f)//重定向
 
{
 
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
 
  return ch;
 
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart==&huart1)
	{
		Rxdata[pt++]=rxdat;
		if(rxdat==1)
		{
			led_mark|=0x08;
		}
		else
		{
			led_mark &= ~0x08;
		}

		HAL_UART_Receive_IT(&huart1,&rxdat,1);//重复开启
	}
}

六、I2C 读取eeprom

官方给的I2C
一定记得初始化PB6 PB7 GPIO_Output

void eeprom_Write(uint8_t addr,uint8_t data)
{
	I2CStart();
	
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CSendByte(data);
	I2CWaitAck();
	
	I2CStop();
	HAL_Delay(10);
	
}

uint8_t eeprom_Read(uint8_t addr)
{
	uint8_t data;
	
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	data=I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	
	return data;
	
}

### 蓝桥杯嵌入式比赛的学习资源与准备 #### 关于蓝桥杯嵌入式比赛的内容概述 蓝桥杯嵌入式比赛主要考察参赛者在硬件设计、软件开发以及实际应用中的综合能力。比赛通常涉及微控制器编程、外设驱动开发、实时操作系统(RTOS)、通信协议实现等内容。对于初学者而言,掌握STM32系列单片机及其生态系统是非常重要的。 为了更好地参与蓝桥杯嵌入式比赛,可以参考以下学习资源和方法: --- #### 推荐学习资源 1. **官方教程与参考资料** 官方提供了详细的竞赛指南和技术文档,这些资料可以帮助理解比赛的具体要求和技术细节[^3]。例如,在文件路径`嵌入式资源数据包_STM32G4_2023\竞赛平台\6-液晶驱动参考程序\MDK5_LCD_HAL\Src`下找到的`lcd.c`源码是一个很好的实践案例,展示了如何编写LCD驱动程序并将其集成到项目中[^2]。 2. **《2024年最新Linux运维全套学习资料》** 尽管这份资料主要是针对Linux运维领域,但它也涵盖了部分嵌入式的基础知识,比如设备驱动开发、交叉编译环境搭建等,这对于嵌入式开发者来说同样重要[^1]。 3. **零基础入门教程** 零基础蓝桥杯嵌入式教程提供了一套完整的入门指导,包括但不限于: - 如何创建一个新的工程项目; - 怎样将必要的头文件(如`fonts.h`)和源文件(如`lcd.c`, `lcd.h`)添加至个人工程目录下的`bsp`文件夹; - 不依赖CubeMX工具的情况下手动完成初始化设置。 --- #### 实践建议 以下是几个具体的实践方向供参考: 1. **熟悉开发板功能模块** 使用指定型号的开发板(通常是基于ARM Cortex-M架构),深入研究其内部结构及各外围接口的功能特性。通过阅读芯片手册了解GPIO、UART、SPI、I2C等常见外设的工作原理。 2. **构建最小系统** 构建一个能够正常运行的基础框架,验证LED闪烁、按键检测等功能是否按预期工作。这是后续复杂任务实施的前提条件之一。 3. **移植第三方库** 学会将现成的开源组件适配到自己的平台上,像FreeRTOS这样的轻量级多线程管理方案就非常适合应用于此类小型控制系统之中。 4. **调试技巧积累** 利用JTAG/SWD接口配合Keil MDK或者STM32CubeIDE进行在线仿真分析错误原因;同时也可以借助串口打印日志信息辅助定位问题所在位置。 --- ```c // 示例代码:简单的延时函数实现 void delay_ms(uint32_t ms){ uint32_t i,j; for(i=ms;i>0;i--){ for(j=800;j>0;j--); } } ``` 上述片段展示了一个简易版毫秒级延迟算法,虽然效率不高但在某些场合仍可满足基本需求。 --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值