模仿 STM32 驱动开发格式实验

news2025/3/15 11:28:24

1.模仿 STM32 寄存器定义

为了开发方便, ST 官方为 STM32F103 编写了一个叫做 stm32f10x.h 的文件,在这个文件
里面定义了 STM32F103 所有外设寄存器,我们可以使用其定义的寄存器来进行开发,比如我 们可以用如下代码来初始化一个 GPIO:
上述代码是初始化 STM32 PE5 这个 GPIO 为推挽输出,需要配置的就是 GPIOE 的寄存
CRL ODR , “GPIOE”的定义:
可以看出“ GPIOE ”是个宏定义,是一个指向地址 GPIOE_BASE 的结构体指针,结构体为
GPIO_TypeDef GPIO_TypeDef 和 GPIOE_BASE 的定义如下:
上述定义中 GPIO_TypeDef 是个结构体,结构体里面的成员变量有 CRL CRH
IDR ODR 、 BSRR、 BRR LCKR ,这些都是 GPIO 的寄存器,每个成员变量都是 32 (4 字节 ) ,这些寄存 器在结构体中的位置都是按照其地址值从小到大排序的。GPIOE_BASE 就是 GPIOE 的基地址, 其为:
GPIOE_BASE 的基地址为 0x40011800 ,宏 GPIOE 指向这个地址,因此 GPIOE 的寄存器
CRL 的地址就是 0X40011800 ,寄存器 CRH 的地址就是 0X40011800+4=0X40011804 ,其他寄存 器地址以此类推。我们要操作 GPIOE ODR 寄存器的话就可以通过“ GPIOE->ODR ”来实现, 这个方法是借助了结构体成员地址连续递增的原理。

2.I.MX6U 寄存器定义 

1、编写外设结构体

先将同属于一个外设的所有寄存器编写到一个结构体里面,如 IO 复用寄存器组的结构体
如下:
//示例代码 11.1.2.1 寄存器 IOMUX_SW_MUX_Type
/* 
 * IOMUX 寄存器组
 */
1 typedef struct
2 {
3 volatile unsigned int BOOT_MODE0;
4 volatile unsigned int BOOT_MODE1;
5 volatile unsigned int SNVS_TAMPER0;
6 volatile unsigned int SNVS_TAMPER1;
………
107 volatile unsigned int CSI_DATA00;
108 volatile unsigned int CSI_DATA01;
109 volatile unsigned int CSI_DATA02;
110 volatile unsigned int CSI_DATA03;
111 volatile unsigned int CSI_DATA04;
112 volatile unsigned int CSI_DATA05;
113 volatile unsigned int CSI_DATA06;
114 volatile unsigned int CSI_DATA07;
/* 为了缩短代码,其余 IO 复用寄存器省略 */
115}IOMUX_SW_MUX_Tpye;
上述结构体 IOMUX_SW_MUX_Type 就是 IO 复用寄存器组,成员变量是每个 IO 对应的复
用寄存器,每个寄存器的地址是 32 位,每个成员都使用“ volatile ”进行了修饰,目的是防止编
译器优化。

2、定义 IO 复用寄存器组的基地址

 

根据结构体 IOMUX_SW_MUX_Type 的定义,其第一个成员变量为 BOOT_MODE0 ,也就
BOOT_MODE0 这个 IO IO 复用寄存器,查找 I.MX6U 的参考手册可以得知其地址为
0X020E0014 ,所以 IO 复用寄存器组的基地址就是 0X020E0014,定义如下:

3、定义访问指针 

访问指针定义如下:
通过上面三步我们就可以通过“ IOMUX_SW_MUX->GPIO1_IO03 ”来访问 GPIO1_IO03
IO 复用寄存器

4.实验程序编写 

本实验对应的例程路径为: 开发板光盘 -> 1 、裸机例程 -> 3_ledc_stm32
创建 VSCode 工程,工作区名字为“ ledc_stm32 ”,新建三个文件: start.S main.c imx6ul.h 。 其中 start.S 是汇编文件, start.S 文件的内容和第十章的 start.S 一样,直接复制过来就可以。 main.c 和 imx6ul.h 是 C 文件,完成以后如图 文件 imx6ul.h 用来存放外设寄存器定义,在 imx6ul.h 中输入如下代码:
/* 
* 外设寄存器组的基地址
*/
1 #define CCM_BASE (0X020C4000)
2 #define CCM_ANALOG_BASE (0X020C8000)
3 #define IOMUX_SW_MUX_BASE (0X020E0014)
4 #define IOMUX_SW_PAD_BASE (0X020E0204)
5 #define GPIO1_BASE (0x0209C000)
6 #define GPIO2_BASE (0x020A0000)
7 #define GPIO3_BASE (0x020A4000)
8 #define GPIO4_BASE (0x020A8000)
9 #define GPIO5_BASE (0x020AC000)
10 
11 /* 
12 * CCM 寄存器结构体定义,分为 CCM 和 CCM_ANALOG 
13 */
14 typedef struct
15 {
16 volatile unsigned int CCR;
17 volatile unsigned int CCDR;
18 volatile unsigned int CSR;
……
46 volatile unsigned int CCGR6;
47 volatile unsigned int RESERVED_3[1];
48 volatile unsigned int CMEOR; 
49 } CCM_Type;
50 
51 typedef struct
52 {
53 volatile unsigned int PLL_ARM;
54 volatile unsigned int PLL_ARM_SET;
55 volatile unsigned int PLL_ARM_CLR;
56 volatile unsigned int PLL_ARM_TOG;
……
110 volatile unsigned int MISC2;
111 volatile unsigned int MISC2_SET;
112 volatile unsigned int MISC2_CLR;
113 volatile unsigned int MISC2_TOG;
114 } CCM_ANALOG_Type;
115
116 /* 
117 * IOMUX 寄存器组
118 */
119 typedef struct
120 {
121 volatile unsigned int BOOT_MODE0;
122 volatile unsigned int BOOT_MODE1;
123 volatile unsigned int SNVS_TAMPER0;
……
241 volatile unsigned int CSI_DATA04;
242 volatile unsigned int CSI_DATA05;
243 volatile unsigned int CSI_DATA06;
244 volatile unsigned int CSI_DATA07;
245 }IOMUX_SW_MUX_Type;
246
247 typedef struct
248 {
249 volatile unsigned int DRAM_ADDR00;
250 volatile unsigned int DRAM_ADDR01;
419 volatile unsigned int GRP_DDRPKE;
420 volatile unsigned int GRP_DDRMODE;
421 volatile unsigned int GRP_DDR_TYPE;
422 }IOMUX_SW_PAD_Type;
423
424 /* 
425 * GPIO 寄存器结构体
426 */
427 typedef struct
428 {
429 volatile unsigned int DR; 
430 volatile unsigned int GDIR; 
431 volatile unsigned int PSR; 
432 volatile unsigned int ICR1; 
433 volatile unsigned int ICR2; 
434 volatile unsigned int IMR; 
435 volatile unsigned int ISR; 
436 volatile unsigned int EDGE_SEL; 
437 }GPIO_Type;
438
439
440 /* 
441 * 外设指针
442 */
443 #define CCM ((CCM_Type *)CCM_BASE)
444 #define CCM_ANALOG ((CCM_ANALOG_Type *)CCM_ANALOG_BASE)
445 #define IOMUX_SW_MUX ((IOMUX_SW_MUX_Type *)IOMUX_SW_MUX_BASE)
446 #define IOMUX_SW_PAD ((IOMUX_SW_PAD_Type *)IOMUX_SW_PAD_BASE)
447 #define GPIO1 ((GPIO_Type *)GPIO1_BASE)
448 #define GPIO2 ((GPIO_Type *)GPIO2_BASE)
449 #define GPIO3 ((GPIO_Type *)GPIO3_BASE)
450 #define GPIO4 ((GPIO_Type *)GPIO4_BASE)
451 #define GPIO5 ((GPIO_Type *)GPIO5_BASE)
在编写寄存器组结构体的时候注意寄存器的地址是否连续,有些外设的寄存器地址可能不
是连续的,会有一些保留地址,因此我们需要在结构体中留出这些保留的寄存器。这个就是
47 RESERVED_3[1] 的来源。 如果不添加保留位来占位的话就会导致寄存器地址错位!
main.c 文件中输入如下所示内容:
1 #include "imx6ul.h"
2 
3 /*
4 * @description : 使能 I.MX6U 所有外设时钟
5 * @param : 无
6 * @return : 无
7 */
8 void clk_enable(void)
9 {
10 CCM->CCGR0 = 0XFFFFFFFF;
11 CCM->CCGR1 = 0XFFFFFFFF;
12 CCM->CCGR2 = 0XFFFFFFFF;
13 CCM->CCGR3 = 0XFFFFFFFF;
14 CCM->CCGR4 = 0XFFFFFFFF;
15 CCM->CCGR5 = 0XFFFFFFFF;
16 CCM->CCGR6 = 0XFFFFFFFF;
17 }
18 
19 /*
20 * @description : 初始化 LED 对应的 GPIO
21 * @param : 无
22 * @return : 无
23 */
24 void led_init(void)
25 {
26 /* 1、初始化 IO 复用 */
27 IOMUX_SW_MUX->GPIO1_IO03 = 0X5; /* 复用为 GPIO1_IO03 */
28 
29 
30 /* 2、配置 GPIO1_IO03 的 IO 属性 
31 *bit 16:0 HYS 关闭
32 *bit [15:14]: 00 默认下拉
33 *bit [13]: 0 kepper 功能
34 *bit [12]: 1 pull/keeper 使能
35 *bit [11]: 0 关闭开路输出
36 *bit [7:6]: 10 速度 100Mhz
37 *bit [5:3]: 110 R0/6 驱动能力
38 *bit [0]: 0 低转换率
39 */
40 IOMUX_SW_PAD->GPIO1_IO03 = 0X10B0;
41 
42
43 /* 3、初始化 GPIO */
44 GPIO1->GDIR = 0X0000008; /* GPIO1_IO03 设置为输出 */
45 
46 /* 4、设置 GPIO1_IO03 输出低电平,打开 LED0 */ 
47 GPIO1->DR &= ~(1 << 3);
48 
49 }
50 
51 /*
52 * @description : 打开 LED 灯
53 * @param : 无
54 * @return : 无
55 */
56 void led_on(void)
57 {
58 /* 将 GPIO1_DR 的 bit3 清零 */
59 GPIO1->DR &= ~(1<<3);
60 }
61 
62 /*
63 * @description : 关闭 LED 灯
64 * @param : 无
65 * @return : 无
66 */
67 void led_off(void)
68 {
69 /* 将 GPIO1_DR 的 bit3 置 1 */
70 GPIO1->DR |= (1<<3);
71 }
72 
73 /*
74 * @description : 短时间延时函数
75 * @param - n : 要延时循环次数(空操作循环次数,模式延时)
76 * @return : 无
77 */
78 void delay_short(volatile unsigned int n)
79 {
80 while(n--){}
81 }
82 
83 /*
84 * @description : 延时函数,在 396Mhz 的主频下
85 * 延时时间大约为 1ms
86 * @param - n : 要延时的 ms 数
87 * @return : 无
88 */
89 void delay(volatile unsigned int n)
90 {
91 while(n--)
92 {
93 delay_short(0x7ff);
94 }
95 }
96 
97 /*
98 * @description : main 函数
99 * @param : 无
100 * @return : 无
101 */
102 int main(void)
103 {
104 clk_enable(); /* 使能所有的时钟 */
105 led_init(); /* 初始化 led */
106
107 while(1) /* 死循环 */
108 { 
109 led_off(); /* 关闭 LED */
110 delay(500); /* 延时 500ms */
111
112 led_on(); /* 打开 LED */
113 delay(500); /* 延时 500ms */
114 }
115
116 return 0;
117 }
main.c 7 个函数,这 7 个函数的含义和第十章中的 main.c 文件一样,只是函数体写法变
了,寄存器的访问采用 imx6ul.h 中定义的外设指针。比如第 27 行设置 GPIO1_IO03 的复用功能就可以通过“IOMUX_SW_MUX->GPIO1_IO03 ”来给寄存 SW_MUX_CTL_PAD_GPIO1_IO03 赋值。

编译下载验证 

编写 Makefile 和链接脚本
Makefile 文件的内容
1 objs := start.o main.o
2 
3 ledc.bin:$(objs)
4 arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^
5 arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
6 arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
7 
8 %.o:%.s
9 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
10 
11 %.o:%.S
12 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
13 
14 %.o:%.c
15 arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
16 
17 clean:
18 rm -rf *.o ledc.bin ledc.elf ledc.dis
编译下载
使用 Make 命令编译代码,编译成功以后使用软件 imxdownload 将编译完成的 ledc.bin
件下载到 SD 卡中,命令如下:
烧写成功以后将 SD 卡插到开发板的 SD 卡槽中,然后复位开发板,如果代码运行正常的
LED0 就会以 500ms 的时间间隔亮灭

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

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

相关文章

订餐|网上订餐系统|基于springboot的网上订餐系统设计与实现(源码+数据库+文档)

网上订餐系统目录 目录 基于springboot的网上订餐系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户功能模块的实现 &#xff08;1&#xff09;用户注册界面 &#xff08;2&#xff09;用户登录界面 &#xff08;3&#xff09;菜品详情界面 &#xff08…

Day-01-02

项目框架搭建 1. 创建父工程 父工程&#xff1a;xuecheng-plus-parent 父工程中没有代码&#xff0c;不用去依赖其它的包&#xff0c;它的作用是限定其它子工程依赖包的版本号&#xff0c;在dependencyManagement 中去编辑即可。 在父工程中只需保留pom.xml文件以及自动生成…

HTTPS网络通信协议基础

目录 前言&#xff1a; 1.HTTPS协议理论 1.1协议概念 1.2加密 2.两类加密 2.1对称加密 2.2非对称加密 3.引入“证书” 3.1证书概念 3.2数据证书内容 3.3数据签名 4.总结 前言&#xff1a; 了解完HTTP协议后&#xff0c;HTTPS协议是HTTP协议的升级加强版&#xff0c…

安装 SEED-XDS560v2 Driver.exe

安装 SEED-XDS560v2 Driver.exe References CCS 5.5.0.00077 安装目录 D:\ti\ccsv5\ SEED-XDS560v2 Driver.exe 安装目录 D:\ti\ccsv5\ccs_base References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/

java实现多级目录树(递归实现)

一.应用场景 有时候需要我们后台给前台传树结构的数据&#xff0c;要怎么查询? 怎么返回数据呢&#xff1f; 二.数据库表设计以及数据内容(以部门举例) id 主键 parent_id 父级部门id depart_name 部门名词 sort 部门排序三.实体类 Data public…

SQL28 计算用户8月每天的练题数量(date_format函数的用法)

代码 select day(date) as day ,count(question_id) as question_cnt from question_practice_detail where date_format(date,%Y-%m)2021-08 group by day知识点 day函数取出日期格式数值里的日期,month,year函数也是类似的作用date_format规定日期/时间的输出格式 %Y 年&am…

JS如何判断普通函数与异步(async)函数

这里可以先打印一下普通函数和异步&#xff08;async&#xff09;函数的结构&#xff0c;如下图 可以看出两者原型链&#xff0c;普通函数的原型链指向的是一个函数&#xff0c;异步&#xff08;async&#xff09;函数原型链指向的是一个AsyncFunction&#xff0c;这时就会想到…

java 培训班预定管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目

一、源码特点 java 培训班预定管理系统是一套完善的java web信息管理系统 采用serlvetdaobean&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xf…

MATLAB导出图程序

本文将以代码的形式快速介绍MATLAB导出图到Paper 1 从simulation导出数 2 与simulation同源文件夹下创建导图m文件 代码如下&#xff1a; % 实验后的数据处理用 M-文件 % clear all % 清空工作空间 % close all      % 关闭所有图形窗口 % load adp.mat …

LeetCode刷题计划

LeetCode刷题计划 推荐 代码随想录&#xff1a;https://github.com/youngyangyang04/leetcode-master 卡码网 练习ACM模式 https://kamacoder.com/ 01 #include <iostream> using namespace std;int main() {int a ,b;while(cin>>a>>b){cout<<ab<…

15-k8s控制器资源-deployment/部署控制器

一、deployment部署控制器概念 在学习rc和rs控制器资源时&#xff0c;我们指导&#xff0c;这两个资源都是控制pod的副本数量的&#xff0c;但是&#xff0c;他们两个有个缺点&#xff0c;就是在部署新版本pod或者回滚代码的时候&#xff0c;需要先apply资源清单&#xff0c;然…

四川古力未来科技公司抖音小店:靠谱的新电商之旅

随着互联网的飞速发展&#xff0c;电商行业日新月异&#xff0c;新兴平台如抖音小店正成为消费者新的购物天堂。在众多抖音小店中&#xff0c;四川古力未来科技公司的店铺以其独特的魅力吸引了众多消费者的目光。那么&#xff0c;四川古力未来科技公司抖音小店到底靠不靠谱呢&a…

OpenCV识别人脸案例实战

使用级联函数 基本流程 函数介绍 在OpenCV中&#xff0c;人脸检测使用的是cv2.CascadeClassifier.detectMultiScale()函数&#xff0c;它可以检测出图片中所有的人脸。该函数由分类器对象调用&#xff0c;其语法格式为&#xff1a; objects cv2.CascadeClassifier.detectMul…

【GPT-2】论文解读:Language Models are Unsupervised Multitask Learners

文章目录 介绍zero-shot learning 零样本学习 方法数据Input Representation 结果 论文&#xff1a;Language Models are Unsupervised Multitask Learners 作者&#xff1a;Alec Radford, Jeff Wu, Rewon Child, D. Luan, Dario Amodei, I. Sutskever 时间&#xff1a;2019 介…

Open CASCADE学习|直纹曲面(ruled surface)

直纹曲面是一类特殊的曲面&#xff0c;在几何学和微分几何中都有研究。它的主要特性是&#xff0c;曲面上的每一点都有至少一条直线经过。换句话说&#xff0c;直纹曲面可以由一条直线通过连续运动构成。在三维欧几里德空间中&#xff0c;最常见的直纹曲面是平面、柱面和锥面&a…

专业140+总410+合工大合肥工业大学833信号分析与处理综合考研经验电子信息与通信工程,真题,大纲,参考书。

经过一年努力奋战&#xff0c;今年初试总分410&#xff0c;其中专业课833信号分析与处理综合&#xff08;ss和dsp&#xff09;140&#xff08;感谢信息通信Jenny老师去年的悉心指导&#xff09;&#xff0c;数一130&#xff0c;顺利上岸&#xff0c;被合工大录取&#xff0c;看…

第三节:基于 InternLM 和 LangChain 搭建你的知识库(课程笔记)

视频链接&#xff1a;https://www.bilibili.com/video/BV1sT4y1p71V/?vd_source3bbd0d74033e31cbca9ee35e111ed3d1 文档地址&#xff1a; https://github.com/InternLM/tutorial/tree/main/langchain 课程笔记&#xff1a; 1.仅仅包含训练时间点之前的数据&#xff0c;无法…

TOP100 图论

1.200. 岛屿数量 给你一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 此外&#xff0c;你可以…

第14讲投票帖子详情实现

投票帖子详情实现 后端,根据id查询投票帖子信息&#xff1a; /*** 根据id查询* param id* return*/ GetMapping("/{id}") public R findById(PathVariable(value "id")Integer id){Vote vote voteService.getById(id);WxUserInfo wxUserInfo wxUserInf…

Python如何实现定时发送qq消息

因为生活中老是忘记各种事情&#xff0c;刚好又在学python&#xff0c;便突发奇想通过python实现提醒任务的功能&#xff08;尽管TIM有定时功能&#xff09;&#xff0c;也可定时给好友、群、讨论组发送qq消息。其工作流程是&#xff1a;访问数据库提取最近计划——>根据数据…