Keil开发STM32单片机项目的三种方式

news2024/11/25 22:27:20

    STM32单片机相比51单片机,内部结构复杂很多,因此直接对底层寄存器编码,相对复杂,这个需要我们了解芯片手册,对于复杂项目,这些操作可能需要反复编写,因此出现了标准库的方式,对寄存器操作进行了封装,操作相对简单。随着项目复杂度提升,又出现了封装更厉害的一种库HAL,这个需要借助STM32CubeMx工具来生成代码。

    简单来说,STM32编码有三种方式:

    1、寄存器编码。

    2、标准库操作编码。

    3、HAL库操作编码。

    这三种方式各有优劣势,寄存器编码更偏向底层,方便我们熟悉单片机内部结构,开发效率相对较低,因为很多初始化,赋值操作需要反复编写,使用HAL库,可以减少大量代码,提高了开发效率,但是不便于理解底层逻辑,需要非常熟练STM32单片机工作逻辑之后才好上手。

    第一种寄存器编码方式,构建项目可以直接新建一个普通项目,如下所示:

 

    项目新建之后,什么也没有,我们需要手动添加一个启动文件和一个main.c文件到工程目录:

 

    我们在keil工具里面,通过添加现有项的方式将这两个文件加到Source Group 1 中,如下所示:

     这个时候,编译会报错:

    说是SystemInit符号未定义,其实是我们构建的项目代码里面(main.c)中缺少SystemInit()方法,添加上就可以了。

    这个项目只有两个文件,一个是启动文件,一个是主程序main.c。我们操作寄存器的代码就在main.c中编写,这里给出一个简单的实现LED灯闪烁的示例代码:

#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE+ 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE+0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE+0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE+0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE+0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE+0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE+0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE+0x2000)

#define GPIOA_ODR_Addr (GPIOA_BASE+12)
#define GPIOB_ODR_Addr (GPIOB_BASE+12)
#define GPIOC_ODR_Addr (GPIOC_BASE+12)
#define GPIOD_ODR_Addr (GPIOD_BASE+12)
#define GPIOE_ODR_Addr (GPIOE_BASE+12)
#define GPIOF_ODR_Addr (GPIOF_BASE+12)
#define GPIOG_ODR_Addr (GPIOG_BASE+12)

#define BITBAND(addr,bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr&0xFFFFF)<<5) + (bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define LED0 MEM_ADDR(BITBAND(GPIOA_ODR_Addr, 5))


typedef struct
{
  volatile unsigned int CR;
	volatile unsigned int CFGR;
	volatile unsigned int CIR;
	volatile unsigned int APB2RSTR;
	volatile unsigned int APB1RSTR;
	volatile unsigned int AHBENR;
	volatile unsigned int APB2ENR;
	volatile unsigned int APB1ENR;
	volatile unsigned int BDCR;
	volatile unsigned int CSR;
}RCC_TypeDef;

#define RCC ((RCC_TypeDef*)0x40021000)

typedef struct
{
	volatile unsigned int CRL;
	volatile unsigned int CRH;
	volatile unsigned int IDR;
	volatile unsigned int ODR;
	volatile unsigned int BSRR;
	volatile unsigned int BRR;
	volatile unsigned int LCKR;
}GPIO_TypeDef;

#define GPIOA ((GPIO_TypeDef*)GPIOA_BASE)

void LEDInit(void)
{
	RCC->APB2ENR|=1<<2;
	GPIOA->CRL &= 0xFF0FFFFF;
	GPIOA->CRL |= 0x00300000;
}

void Delay_ms(volatile unsigned int t)
{
  unsigned int i,j;
	for(j=0;j<t;j++)
	  for(i=0;i<800;i++);
}

void SystemInit(void)
{

}

int main(void)
{
	LEDInit();
	while(1)
	{
	  LED0 = 0;
		Delay_ms(500);
		LED0 = 1;
		Delay_ms(500);
	}
}


    项目构建成功,不报错就可以进行仿真,或者下载到单片机调试。

    第二种方式,直接在Keil工具中构建STM32标准库工程,不用额外拷贝标准库文件到项目文件夹,然后添加现有项的方式加入组中,构建项目,选择芯片系列之后,在弹出确认框这里可以选择需要的库:

    这里勾选CMSIS->CORE, Device->Startup , Device->StdPeriph Drivers->Framework,GPIO,RCC几项。

    自动生成的代码结构如下所示:

    这里面除了main.c是手动添加的,其余的都是通过keil自动生成的,如果你做过手动添加标准库,那么就会很熟悉这里面的一些文件,stm32f10x_gpio.c,stm32f10x_rcc.c,startup_stm32f10x_ld.s,system_stm32f10x.c。

    这里直接编译会报错:

    Error: L6218E: Undefined symbol assert_param (referred from misc.o).

    这个问题是找不到assert_param这个函数,而这个函数是在stm32f10x_conf.h中,从上面的工程结构,我们看到代码里面是有stm32f10x_conf.h这个头文件的。解决办法就是使用宏定义USE_STDPERIPH_DRIVER查找:

    点击魔法棒工具Options for Targets,在弹出框中选择c/c++,Define处输入USE_STDPERIPH_DRIVER,Include Paths指定当前项目路径下的RTE目录即可。

    最后可以编译成功。

    这里也给出一段让LED闪烁的代码。

#include "stm32f10x.h"

void Delay()
{
  unsigned int i,j;
	for(i=0;i<1000;i++)
	  for(j=0;j<1000;j++);
}

void LED_Config()
{
    GPIO_InitTypeDef GPIO_InitStructure;                 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;             
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;     
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

int main(void)
{
	LED_Config();
	while(1)
	{
	    GPIO_SetBits(GPIOA, GPIO_Pin_5);
		Delay();
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
		Delay();
	}
}

    PA5口作为电平输出, 时钟使能与GPIO初始化,都调用标准库中的方法。

    第三种构建STM32工程的方法需要借助STM32CubeMx工具,这个是免费的,安装之后,可以图形化界面操作,如下所示:

    1)打开工具之后,新建工程,来到选择芯片界面:

    这里在Commecial Part Number这里输入STM32F103会自动补全C6A,选中右侧面板中的一个芯片双击,

   2)进入配置界面。

    展开System Core菜单,默认选中SYS,我们点击,在中间模式这里选择Debug: Serial Wire。

    然后,选中RCC

    设置HSE/LSE为Crystal/Ceramic Resonator。改变之后,右侧芯片会有变化。

    接着,还要将芯片上的PA5端口作为GPIO_Output,点击PA5,就会出现菜单选项,直接选择即可。 

   3)工程位置及编译工具设置

    设置工程名,工程位置,Toolchain/IDE选择MDK-ARM,版本选择V5。

    4)代码生成。点击GENERATE CODE按钮。

    5)生成的代码,可以直接用Keil打开,结构如下:

 

    连main.c都写好了,直接编译也没有问题。我们要实现LED闪烁,只需要在while(1)循环体中增加如下代码:

  while (1)
  {
    /* USER CODE END WHILE */
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
	HAL_Delay(200);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
	HAL_Delay(200);
    /* USER CODE BEGIN 3 */
  }

    这种方式生成的代码,不仅帮我们做了很多工作,甚至连编译准备都做好了,我们看看Options for Targets的c/c++选项:

 

   宏定义查找设置了,不用我们手动设置,另外编译生成hex文件,也同样帮我们勾选好了。

   使用HAL库,自己编写的代码很少,但是理解起来需要花时间,默认操作做了什么,这里面隐含了哪些操作。   

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

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

相关文章

医药反腐正当时!以此为鉴,企业采购腐败怎么防?

近日&#xff0c;医药行业正在经历一场力度空前的反腐风暴。今年以来&#xff0c;全国通报的多起医药腐败案件中&#xff0c;主要涉及通过在药品采购、医疗器械及耗材采购等事项上为他人谋取利益&#xff0c;收受贿赂等问题&#xff0c;涉及金额算下来更是惊人。 医药行业的采购…

深入源码分析kubernetes informer机制(三)Resync

[阅读指南] 这是该系列第三篇 基于kubernetes 1.27 stage版本 为了方便阅读&#xff0c;后续所有代码均省略了错误处理及与关注逻辑无关的部分。 文章目录 为什么需要resyncresync做了什么 为什么需要resync 如果看过上一篇&#xff0c;大概能了解&#xff0c;client数据主要通…

OpenSSL 远程升级到 3.2.1

OpenSSL 远程升级到 3.2.1 文章目录 OpenSSL 远程升级到 3.2.1背景升级 OpenSSL1. 查看 OpenSSL版本2. 下载最新稳定版本 OpenSSL3. 解压缩&#xff0c;安装4. 配置 背景 最近的护网行动&#xff0c;被查出来了好几个关于OpenSSH的漏洞。需要升级OpenSSH&#xff0c;升级OpenS…

Postman通用接口加密解决方案

前言&#xff1a; 很对小伙伴对于psotman接口加密不知道如何解决&#xff0c;这里给大家出了一个全网最详细的解决方案&#xff0c;希望能帮助到大家 问题 postman内置加密Api&#xff0c;但不支持RSA加解密码。如何用postman进入rsa加解密&#xff1f;postman中request对象…

【机器学习5】数据处理(二)Pandas:表格处理

Pandas:表格处理 &#x1f31f;&#x1f31f;Pandas三种数据类型✨✨Series数据结构✨✨ DataFrame数据结构&#x1f319;&#x1f319;DataFrame数据的选取&#x1f315;&#x1f315;DataFrame的构建&#x1f315;&#x1f315;选取多行&#x1f315;&#x1f315;选取某一列…

Qt应用开发(基础篇)——滚屏区域类 QScrollArea

一、前言 QScrollArea类继承于QAbstractScrollArea&#xff0c;QAbstractScrollArea继承于QFrame&#xff0c;是Qt滚动视图的常用部件。 滚屏区域基类 QAbstractScrollArea 框架类 QFrame QScrollArea类提供了对另一个小部件的滚动视图&#xff0c;基础功能、滚动条控制、界面策…

Java后端开发需要学什么知识?这些足以影响你的成就

Java后端开发需要学什么知识?如果你的理想是成为一名优秀的Java程序员&#xff0c;那么确实是需要具备一定的技术实力的&#xff0c;后端开发涉及到处理服务器端逻辑、数据库操作、性能优化、安全性等方面&#xff0c;因此需要掌握一定的技术知识和技能。 需要掌握哪些后端开发…

数据分片概述、环境准备、部署MyCAT服务、全局表、分片表、ER表

Top NSD DBA DAY08 案例1&#xff1a;部署mycat服务案例2&#xff1a;测试配置 1 案例1&#xff1a;部署mycat服务 1.1 问题 把主机mysql60 配置为 MySQL59 的从服务器把主机mysql62 配置为 MySQL61 的从服务器把主机mycat63 配置为mycat服务器客户端192.168.88.50访问myca…

实验记录——TT

8月份的小小实验 安装虚拟环境下载相关软件功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注释也…

Flask Web开发实战(狼书)| 笔记第1、2章

前言 2023-8-11 以前对网站开发萌生了想法&#xff0c;又有些急于求成&#xff0c;在B站照着视频敲了一个基于flask的博客系统。但对于程序的代码难免有些囫囵吞枣&#xff0c;存在许多模糊或不太理解的地方&#xff0c;只会照葫芦画瓢。 而当自己想开发一个什么网站的时&…

关于 Windows 11 的云端备份

一、Windows 云端备份不是Windows 11专享 Windows 11即将正式推出一项云端备份功能&#xff0c;它的作用是为您备份几乎所有内容 - 不仅仅是您的文件和文件夹&#xff0c;还包括应用程序、系统设置、登录详细信息等&#xff0c;以便您可以立即启动并运行新电脑。这些详细信息与…

【Vue2】动态组件的使用-切换组件和keep-alive,以及异步组件

目录 想实现切换不同列表展示不同数据方法一方法二&#xff0c;动态组件动态组件的父组件如何传的值动态组件的子组件如何接受传的值 认识keep-alive缓存组件的生命周期 异步组件&#xff0c;单独打包&#xff0c;实现webpack分包&#xff0c;如何对组件进行单独打包&#xff0…

实习笔记(一)

自定义注解&#xff1a; 自定义注解中有三个元注解Target,Retention,Document /*** 系统日志注解** author Mark sunlightcsgmail.com*/ Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) Documented public interface SysLog {String value() default "…

react-router-dom6 路由不合法

1、昨天用react-router-dom6搭建了个项目&#xff0c;简直了&#xff0c;一个bug直接给我应用干废了&#xff01; 2、我试了试不合法的url是如何处理的&#xff0c;随意输入了个反斜杠 http://localhost:8089/#/\ 3、结果应用搞岔气了&#xff0c; 意思是我的url不合法。 这没问…

Qt creator之对齐参考线——新增可视化缩进功能

Qt creator随着官方越来越重视&#xff0c;更新频率也在不断加快&#xff0c;今天无意中发现qt creator新版有了对齐参考线&#xff0c;也称可视化缩进Visualize Indent&#xff0c;默认为启用状态。 下图为旧版Qt Creator显示设置栏&#xff1a; 下图为新版本Qt Creator显示设…

ctfshow—萌新—web1

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 解法1 标准的数字型注入 查列名 http://cc3ecc3f-8c42-4624-979e-277a51ea85d2.challenge.ctf.show/?id1%20union%20select%20table_name,column_name,3%20from%20information_schema.columns%20where%20t…

Linux—LVM基础

Linux—LVM 一、什么是LVM二、LVM名词解释三、LVM的写入模式四、LVM的工作原理五、LVM的优缺点六、创建PV/VG/LV的方法补充说明 一、什么是LVM LVM&#xff08;Logical Volume Manager&#xff09;&#xff0c;即逻辑卷管理&#xff0c;是Linux环境下对磁盘分区进行管理的一种…

校园宿舍管理系统java学生楼层宿管 jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 校园宿舍管理系统 系统有1权限&#xff1a;管理员 二…

代码随想录算法训练营第三十六天|背包理论基础,LeetCode 416

目录 背包理论基础 动态规划五步曲&#xff1a; 1.确定dp[i][j]的含义 2.找出递推公式 3.初始化dp数组 4.确定遍历顺序 5.举例dp数组 背包理论基础II 动态规划五步曲&#xff1a; 1.确定dp[j]含义 2.找出递推公式 3.初始化dp数组 4.确定遍历顺序 5.举例dp数组 L…

[MAUI]在.NET MAUI中实现可拖拽排序列表

.NET MAUI 中提供了拖放(drag-drop)手势识别器&#xff0c;允许用户通过拖动手势来移动控件。在这篇文章中&#xff0c;我们将学习如何使用拖放手势识别器来实现可拖拽排序列表。在本例中&#xff0c;列表中显示不同大小的磁贴&#xff08;Tile&#xff09;并且可以拖拽排序。 …