首页 > 其他分享 >蓝桥杯嵌入式的学习总结

蓝桥杯嵌入式的学习总结

时间:2024-09-22 22:22:10浏览次数:11  
标签:总结 HAL ccrl htim 嵌入式 蓝桥 TIM GPIO 输入

一. 前言

        嵌入式竞赛实训平台(CT117E-M4) 是北京国信长天科技有限公司设计,生产的一款 “ 蓝桥杯全国软件与信息技术专业人才大赛-嵌入式设计与开发科目 “ 专用竞赛平台,平台以STM32G431RBT6为主控芯片,预留扩展板接口,可为用户提供丰富的实验场景。

以下内容都是小编自己在学习中所总结摘抄下来内容以及对嵌入式竞赛实训平台的相关理解,如有不到位之处,可尽情指出。如果全部完全理解掌握,拿个省二完全绰绰有余。

二. 学习CT117E-M4开发板

        1. 首先需要了解开发板资源,可以通过查看CT117E-M4的产品手册获取相对应的知识。另外在开始学习前,需要准备好相对应的软件环境,包括嵌入式集成开发环境(Keil Realview MDK) 以及STM32CubeMx的相关环境配置。值得注意的是如果使用keil 5 集成开发环境,就得使用集成开发环境自带的Pack installer安装STM32G4系列器件包。这些资源我都会放在我主页的资源当中,如果有需要可以取走。

        2. 在蓝桥云课上的右上角的搜索处输入蓝桥杯大赛历届真题即可查找到历届真题。

        3. LED是由PC8~PC15这8个GPIO口控制,在低电平时候点亮,所以我们在初始化时就可以在CubeMX中让它们都置高。如下所示:

如上图所示,就实现了将PC8~PC15所有的GPIO口都置为高,因此刚开始所以LED灯都会灭。

        4.  GPIO端口总共有八种模式,输入模式有四种:上拉输入模式,下拉输入模式,浮空输入,模拟输入。输出模式有:推挽输出,开漏输出,复用推挽,复用开漏。

        5. 这里简单介绍下这八种模式的概念:

1)上拉输入模式:上拉开关闭合,下拉开关断开,肖特基触发器打开。当IO引脚没有外部输入时,GPIO引脚会默认输入一个高电平,可以通过读取输入数据寄存器来读取到此时的IO电平。

2)下拉输入模式则跟上拉输入模式相反。

3)浮空输入模式:上拉开关和下拉开关均断开,肖特基触发器打开。此时,如果外部的IO引脚什么都不接(即悬空状态),此时GPIO引脚的电平将是一个不确定的状态。它将完全由外部的输入电平来确定。

4)模拟输入模式:肖特基触发器关闭,数据不再经过触发器模块。并且内部上下拉全部断开。该模式一般是给芯片内部的ADC外设来使用的。在该模式下,可以知道MCU将无法通过读取输入数据寄存器获得IO引脚的电平变化状态。

5)推挽输出模式:可输出高低电平,驱动能力强。

6)开漏输出模式:只能输出低电平,需要外部上拉电阻才能输出高电平。

7)复用推挽输出模式:用于特殊功能如UART、SPI等,由其他外设控制输出。

8)复用开漏输出模式:同样用于特殊功能,由其他外设控制输出。

        6. 代码书写的位置:

1)private includes:用户头文件的引用。

2)private typedef:用户自定义数据类型。

3)private macro:用户宏函数定义。

4)private variables:用户常量和变量定义。

5)private function prototypes:用户函数说明。

6)private usercode:功能实现位置。

7)Initialize all configured peripherals:各种初始化位置。

        7. 大家在安装完Keil集成开发环境后,需要选择CMSIS-DAP Debugger调试器,然后点击setting就能进入下面这个界面,然后再在Flash选项卡下,勾选Reset and Run。

 

三. 开发板各个外设的配置及使用

        1. 首先从LED灯开始,由于上面已经讲过LED的CubeMx配置,所以我们直接来看下由CubeMx生成的keil 5工程代码中LED相关代码。

#include"led.h"

void LED_Disp(uchar dsLED)
{
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);	//hign pin
	HAL_GPIO_WritePin(GPIOC,dsLED<<8,GPIO_PIN_RESET);	//some low
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);	//open Latch
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);	//close Latch
}

 

其中,HAL_GPIO_WritePin这个就是HAL库中的一个内置函数,用来设置引脚电平。

下面我们再来看下led.h的代码,我们在每创建一个.c和.h文件后都要保存到相应工程目录的一个文件夹中,这里可以统一命名为bsp。

#ifndef _LED_H_
#define _LED_H_

#include "main.h"

void LED_Disp(uchar dsLED);

#endif

 

其中bsp文件夹就是存放的我们各种.c和.h文件,MDK-ARM中就有我们的keil5工程,下面那个test.ioc就是我们相应的CubeMx配置。在有了文件夹后,别忘了在keil5工程左侧目录中添加这个文件夹哦。最后一步就是让这个包含所有内容的总文件夹成为我们keil5工程的环境变量,点击keil5工程上方一个类似魔法棒的东西,然后选择其中的Include Paths如下所示:

  

        2.  关于LCD的相关代码在官方给出的资料当中就有,我们可以直接拿过来使用。这里小编后面也会整理在我主页的资料当中。

        3. 按键控制,通过查询产品手册,可以知道按键主要由PB1,PB2,PB0,PA0控制。

相关按键代码示例如下:

#include "interrupt.h"
#include "main.h"

struct keys key[4]={0,0,0,0};
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	 if(htim->Instance==TIM1)
	 {
			key[0].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
			key[1].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
			key[2].key_sta=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
			key[3].key_sta=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		 
		 for(int i=0;i<4;i++)
		 {
				switch(key[i].judge_sta)
				{
					case 0:
					{
						if(key[i].key_sta==0)
						{
							key[i].judge_sta=1;
							key[i].key_time=0;
						}
					}
					break;
					case 1:
					{
						if(key[i].key_sta==0)
						{
								key[i].judge_sta=2;
						}
						else
						{
							key[i].judge_sta=0;	
						}
					}
					break;
					case 2:
					{
						if(key[i].key_sta==1)
						{
							key[i].judge_sta=0;
							if(key[i].key_time<70)
							{
								key[i].single_flag=1;
							}
						}
						else
						{
							key[i].key_time++;
							if(key[i].key_time>70)
							{
								key[i].long_flag=1;
							}
						}
					}
					break;
				}
		 }
	 }
}

 

这里包含了按键的点击,长按的判断,并且使用到了定时器作为中断,用来间隔很短的时间来查询按键是否被按下。

下面我们来看下相关的CubeMx配置。

 

这里我们使用的是定时器TIM1,需要设置Clock Source为Internal Clock内部时钟源。并且在下面设置好分频系数(Prescaler)以及重装载值(Counter Period)。这里为什么设置成80-1,主要是根据频率和时间的关系来确定的。我们知道频率的倒数就是所间隔的时间,例如50Hz就是0.02s。因为在我们的产品手册中说明了频率为80MHz,也就是80000000,我们用这个数除以分频系数,再除以重装载值就是我们最后的定时器间隔时间。这里80000000除以80得1000000,再除以10000,得100,也就是100Hz,0.01s,10ms。之所以减一是因为这里从0开始。

为了方便,这里我把我们今天所讲到的内容所涉及到的GPIO配置直接给出来。

3. PWM输入捕获

        与PA6和PA7有关,选择TIM16_CH1和TIM17_CH1。

 

 

 

double ccrl_val1a=0,ccrl_val2a=0;
uint ccrl_val1b=0,ccrl_val2b=0;
uint frq1=0,frq2=0;
float duty1=0,duty2=0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM2)
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
			{
		ccrl_val1a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		ccrl_val1b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);
		__HAL_TIM_SetCounter(htim,0);
		frq1=(80000000/80)/ccrl_val1a;
		duty1=(ccrl_val1b/ccrl_val1a)*100;
		HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
		HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
			}
	}
	if(htim->Instance==TIM3)
	{
		if(htim->Channel==HAL_TIM_ACTIVE_CHANNEL_1)
			{
		ccrl_val2a=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
		ccrl_val2b=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_2);
		__HAL_TIM_SetCounter(htim,0);
		frq2=(80000000/80)/ccrl_val2a;
		duty2=(ccrl_val2b/ccrl_val2a)*100;
		HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
		HAL_TIM_IC_Start(htim,TIM_CHANNEL_2);
			}
	}
}

4. ADC数模转化

        

 

#include "badc.h"

double getADC(ADC_HandleTypeDef *pin)
{
	double abc;
	HAL_ADC_Start(pin);
	abc = HAL_ADC_GetValue(pin);
	return (abc*3.3)/4096.0;
}

 

5. IIC通信

相关硬件配置如下: 

        

由此可以得出我们的IIC通信跟PB6和PB7有关。

关于IIC通信的相关代码,我们也可以直接使用官方所给的资料当中的代码,我们只需要在此基础上再添加两个代码即可,也就是IIC通信的读取和写入。如下所示:

unsigned char eeprom_read(unsigned char addr)
{
	unsigned char dat;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CStop();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	dat=I2CReceiveByte();
	I2CSendAck();
	I2CStop();
	return dat;
}

void eeprom_write(unsigned addr,unsigned char dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

以上便是我们今天的全部内容,如还有些许疑问,可以直接私信我或者在评论区底下留言。另外所需的资源数据包以及相关的完整源代码文件可在我主页中进行查找,或者找我拿取。

 

         

 

 

 

 

 

 

 

标签:总结,HAL,ccrl,htim,嵌入式,蓝桥,TIM,GPIO,输入
From: https://blog.csdn.net/2303_78660417/article/details/142443489

相关文章

  • Python 客户端类库之paho-mqtt学习总结
    实践环境Python3.9.13paho-mqtt2.1.0简介EclipsePahoMQTTPython客户端类库实现了MQTT协议版本5.0,3.1.1,和3.1。该类库提供一个客户端类,允许应用连接到MQTT代理并发布消息,订阅主题并检索发布的消息。同时还提供了一个写其它辅助函数,使向MQTT服务器发布一次性消息变......
  • Redis从基础到实战总结+Redisson分布式锁小结
    一、NoSQL和RDBMS的区别传统的rdbms结构化组织SQL数据和关系都存储在单独的表中操作语言是数据库定义语言严格的一致性基础的事务NoSql不仅仅是数据没有固定的语言键值对存储,列存储、文档存储、图形数据库最终一致性cpa定理和base高性能,高可用,高可扩二、NoSql的四大分类......
  • 关于 最短路 及其 拓展算法 的粗浅总结
    关于最短路及其拓展算法的粗浅总结最短路(Dijkstra)Core_Codeinlinevoiddijkstra(){memset(vis,0,sizeofvis); memset(dis,0x3f,sizeofdis);dis[s]=0;priority_queue<pair<int,int>>q;q.push(make_pair(dis[s],s));while(!q.empty()){......
  • Mybatis相关知识总结
    目录1.什么是Mybatis?2.Mybatis所提供的功能?3.MyBatis的优缺点是什么?4.为什么说mybatis是半自动化orm映射工具?它与全自动的区别在哪里?5.Hibernate和Mybatis的区别?6.JDBC编程有哪些不足之处?Mybatis是如何解决这些问题的?7.Mybatis编程步骤是什么样的?【简化:见下】【详细:......
  • Tarjan算法及其应用 总结+详细讲解+详细代码注释
    \(\text{Tarjan}\)1.引入概念1.强连通分量1.定义在有向图\(G\)中,强连通分量就是满足以下条件的\(G\)的子图:从任意一点出发,都有到达另一个点的路径。不存在一个或者几个点,使得这个子图加入这些点后,这个子图还满足上一个性质。为什么要限定”在有向图中“而不是”在任......
  • 【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解
    【洛谷】P10417[蓝桥杯2023国A]第K小的和的题解题目传送门题解CSP-S1补全程序,致敬全A的答案,和神奇的预言家。写一下这篇的题解说不定能加CSP2024的RP代码#include<bits/stdc++.h>#definelowbit(x)x&(-x)#defineendl"\n"usingnamespacestd......
  • NOIP2024模拟赛7 总结
    NOIP2024模拟赛7总结A.恰钱没啥好说的。赛场就过了。比较难蚌的是,第一遍本地测的时候没有写spj,导致我们很多人T1都直接挂零了。不过后来配上重测了。B.排序由于某种神秘原因,导致线段树build写的范围是\(1\simn+1\),update的时候写的也是\(1\simn+1\),然而que......
  • xss跨站漏洞总结
    1.原理指攻击者利用网站程序对用户输入过滤的不足,输入可以显示在页面对其他用户造成影响的HTML代码工具,从而盗取资料,获得管理员信息等。通俗来讲,xss跨站攻击就是寻找输入输出的地方,如url地址处的输入,留言板的输入,来进行js代码的注入,从而获取信息。输入地点:get,post,header,......
  • 【蓝桥杯】2024.9.22算法赛——灵魂问题\全栈项目小组(C++)
    一、灵魂问题题目灵魂问题题目分析1.要求输出一个整数2.题目在玩脑筋急转弯,关键句子标出来了——糖什么的根本不重要。所以咖啡不加糖,答案是0!!!代码#include<iostream>usingnamespacestd;intmain(){ cout<<0; return0;}二、全栈项目小组题目全栈项目小组......
  • torch模型量化方法总结
    0.概述模型训练完成后的参数为float或double类型,而装机(比如车载)后推理预测时,通常都会预先定点(量化)为int类型参数,相应的推理的精度会有少量下降,但不构成明显性能下降,带来的结果是板端部署的可能性,推理的latency明显降低,本文对torch常用的量化方法进行总结作为记录。1.模型量化......