蓝桥杯嵌入式的学习总结

news2024/12/24 11:34:44

一. 前言

        嵌入式竞赛实训平台(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();
}

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

 

         

 

 

 

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2156337.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构篇--顺序查找【详解】

概念章 查找就是在数据集合中寻找某种条件的数据元素的过程。 查找表是指用于查找同一类型的数据元素集合。 找到了满足条件的数据元素&#xff0c;就是查找成功&#xff0c;否则就是称为查找失败。 关键字是指数据元素的某个数据项的值&#xff0c;可用于标识或者记录&…

【Java】线程暂停比拼:wait() 和 sleep()的较量

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 在Java多线程编程中&#xff0c;合理地控制线程的执行是至关重要的。wait()和sleep()是两个常用的方法&#xff0c;它们都可以用来暂停线程的执行&#xff0c;但它们之间存在着显著的差异。本文将详…

【AI学习笔记】初学机器学习西瓜书概要记录(二)常用的机器学习方法篇

初学机器学习西瓜书的概要记录&#xff08;一&#xff09;机器学习基础知识篇(已完结) 初学机器学习西瓜书的概要记录&#xff08;二&#xff09;常用的机器学习方法篇(持续更新) 初学机器学习西瓜书的概要记录&#xff08;三&#xff09;进阶知识篇(待更) 文字公式撰写不易&am…

Django 基础之启动命令和基础配置

Django启动 django启动一般可以通过ide或者命令启动 ide启动&#xff1a; 启动命令&#xff1a; python manage.py runserver该命令后续可以增加参数&#xff0c;如&#xff1a; python manage.py runserver 8081 python manage.py runserver 127.0.0.1:8082 注意&#xff1…

StopIteration: 迭代停止完美解决方法 ️

&#x1f504; StopIteration: 迭代停止完美解决方法 &#x1f6e0;️ &#x1f504; StopIteration: 迭代停止完美解决方法 &#x1f6e0;️摘要引言正文1. 什么是StopIteration异常&#xff1f;&#x1f4dc;2. StopIteration在for循环中的处理机制&#x1f6a6;3. 如何自定…

数仓规范:命名规范如何设计?

目录 0 前言 1 表命名规范 2 字段命名规范 3 任务命名规范 4 层级命名规范 5 自定义函数命名规范 6 视图和存储过程的命名规范 7 综合案例分析 8 常见陷阱和如何避免 9 工具和最佳实践 10 小结 想进一步了解数仓建设这门艺术的&#xff0c;可以订阅我的专栏数字化建设…

深度学习02-pytorch-03-张量的数值计算

张量&#xff08;Tensor&#xff09;是多维数组的通用化概念&#xff0c;它可以表示标量&#xff08;0维&#xff09;、向量&#xff08;1维&#xff09;、矩阵&#xff08;2维&#xff09;以及更高维度的数据。在深度学习和数值计算中&#xff0c;张量是基础数据结构&#xff…

[Python学习日记-27] 文件操作练习题解析

[Python学习日记-27] 文件操作练习题解析 简介 练习题1——全局替换程序 练习题2——模拟登陆 简介 练习题1——全局替换程序 一、题目 写一个脚本&#xff0c;允许用户按以下方式执行时填入参数&#xff0c;即可以对指定文件内容进行全局替换 python your_script.py old…

Mybatis in用法优化

如果in的参数过多&#xff0c;mybatis会报错 原来写法&#xff1a;select * from file_inf a <where>and a.status 0 and a.id in<foreach collection"ids" open"(" close")" separator"," item"id" #{id}</for…

ConflictingBeanDefinitionException | 运行SpringBoot项目时报错bean定义冲突解决方案

具体报错&#xff1a; Caused by: org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name ‘CommissionMapperImpl’ for bean class [com.xxx.mapper.carrier.CommissionMapperImpl] conflicts with existing, non-co…

MAC激活Typora以及禁止成功激活弹窗的方法

激活 Typora 首先在官网下载 Typora 的最新版 并且安装。 打开以下目录 /Applications/Typora.app/Contents/Resources/TypeMark/page-dist/static/js/ 注意在 Applications 中&#xff0c;需要对 Typora 右键选择 Show Packages Contents 即可进入 Typora.app。 在该目录的文…

探索未来智能:Moonshot AI 引领AI新纪元——M1超级模型

在人工智能的快速演进中&#xff0c;Moonshot AI再次站在了技术创新的前沿。推出M1超级模型&#xff0c;这是一款旨在突破现有AI能力极限的革命性产品。 M1超级模型的诞生背景 随着数据量的爆炸性增长和计算能力的提升&#xff0c;AI模型正变得越来越复杂和强大。M1超级模型…

华为HarmonyOS地图服务 1 -- 如何实现地图呈现?

如何使用地图组件MapComponent和MapComponentController呈现地图&#xff0c;效果如下图所示。 MapComponent是地图组件&#xff0c;用于在您的页面中放置地图。MapComponentController是地图组件的主要功能入口类&#xff0c;用来操作地图&#xff0c;与地图有关的所有方法从此…

从规范到实现解读Windows平台如何播放RTSP流

RTSP播放器应用场景 RTSP播放器在视频监控、远程视频会议、网络电视、实时流媒体传输、协同操控相关的智能设备、教育培训以及企业内部通讯与协作等多个领域都有着广泛的应用场景。 1. 视频监控 RTSP直播播放器在视频监控系统中扮演着重要角色。通过RTSP协议&#xff0c;播放…

Java—SPI 机制详解

参考文章 Java常用机制 - SPI机制详解 | Java 全栈知识体系包含: Java 基础, Java 部分源码, JVM, Spring, Spring Boot, Spring Cloud, 数据库原理, MySQL, ElasticSearch, MongoDB, Docker, k8s, CI&CD, Linux, DevOps, 分布式, 中间件, 开发工具, Git, IDE, 源码阅读&a…

安全带检测系统源码分享

安全带检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Visio…

OpenCV基础入门30讲(Python)——第三讲 图像对象的创建与赋值

在OpenCV里&#xff0c;对图像的操作是最为基本的。接下来我们看一下图像对象的创建与赋值。 注&#xff1a;前文介绍过的代码和操作不再重复。 代码 在 main 文件中&#xff0c;先导入新的模块 # 导入 numpy 模块&#xff0c;重命名为 np import numpy as np 再写进以下代…

一条龙小程序开发教程

初次上手 微信小程序已经成为国内前端的一个重要业务&#xff0c;跟 Web 和手机 App 有着同等的重要性。小程序开发者供不应求&#xff0c;市场招聘需求极其旺盛&#xff0c;企业都抢着要。 尽管如此&#xff0c;小程序的教程却很缺&#xff0c;要么是不够系统&#xff0c;要么…

Python 从入门到实战24(类的继承)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们讨论了类的定义、使用方法、property的相关知识。今…

PHP API 框架:构建高效API的利器

在当今快速发展的互联网时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同应用程序和服务的关键。PHP&#xff0c;作为一种流行的服务器端脚本语言&#xff0c;提供了多种强大的框架来简化API的开发。本文将介绍PHP API框架的重要性&#xff0c;以及…