[DAY 5] _stm32f103c8t6开发板暂存器开发_控制MCU的GPIO High、Low范例

想走嵌入式系统开发这行必经的路,直接了解最底层怎麽运作的,Arduino底层也是这样运作的,只是Arduino把这些操作都包起来写成一个函式给你使用,叫出那函式输入对的值就能直接使用。

我在DAY3DAY4的时候有先教学如何安装环境,在第四天的最後先创了两个空档(main.c、stm32f103.h),还有从标准库复制了1个.s档,这个.s档是用组合语言所写的,MCU一上电第1个执行的地方,是1个启动的档案。

首先,先打stm32f103.h,这里面是要配置暂存器位置,如下图
https://ithelp.ithome.com.tw/upload/images/20210918/20141979veKX2oPoek.png

stm32f103.h 程序码:

//外设基本地址,在datasheet的Memory map(内存映射)里看的到
#define PERIPA_BASE          ((unsigned int)0x40000000)   

//基本地址加上20000是因为所有GPIO口在这地址上,( APB2PERIPH_BASE=0x4000 0000+0x0001 0000=0x4001 0000)
#define APB2PERIPH_BASE		 (PERIPA_BASE + 0x00010000) 

//GPIOA这个IO口的地址,"A"的,专属於A的!!
#define GPIOA_BASE           (APB2PERIPH_BASE+0x0800)

//这一部份是Reference manual(参考手册)上的GPIO章节所介绍的所有能配置功能的暂存器
//全部基本位置加上偏移位置就到单1那个GPIO口的实际位置了
#define GPIOA_CRL			*(unsigned int*)(GPIOA_BASE+0x00)                                        
#define GPIOA_CRH			*(unsigned int*)(GPIOA_BASE+0x04)                                        
#define GPIOA_IDR			*(unsigned int*)(GPIOA_BASE+0x08)                                        
#define GPIOA_ODR			*(unsigned int*)(GPIOA_BASE+0x0C)                                        
#define GPIOA_BSRR			*(unsigned int*)(GPIOA_BASE+0x10)                                        
#define GPIOA_BRR			*(unsigned int*)(GPIOA_BASE+0x14)                                        
#define GPIOA_LCKR			*(unsigned int*)(GPIOA_BASE+0x18)                                        
	
//RCC外设基本地址
#define RCC_BASE            (0x40021000)

//RCC_控制GPIO口时钟的实际地址
#define RCC_APB2ENR			*(unsigned int*)(RCC_BASE+0x18)

逐行解释,#define是C语言的定义,我打左边的暂存器名称会等於右边的指向地址
#define PERIPA_BASE,这是指我总线的地址,先来看看Reference manual里提供的记忆体的地图:
https://ithelp.ithome.com.tw/upload/images/20210918/20141979QzC8i8Z5ro.png
看到上土左半边的位置范围,对上右边每个位置的名称,这样就可以查询你要的功能在哪个范围!,我说的是范围喔!,时记的偏移位置要再加上去,来举#define GPIOA_BSRR为例:
先开Reference manua找对应的暂存器位置说明:
https://ithelp.ithome.com.tw/upload/images/20210918/20141979Pu0QbKmRuK.png
看到左半边的目录位置,点选BSRR後会跳进来,在看右边上方有个Address offser:0x10再去看看我的程序码,这就是实际的位置啦~~
同理再来设置RCC时钟,有时中GPIO口才会开始工作,可以先看我上上个记忆体地图,我有框起来RCC的基本位置从0x4002 1000 开始
https://ithelp.ithome.com.tw/upload/images/20210918/20141979ccVOlBkcZL.png
再来是实际的位置,加上0x18

这样都配置完地址了~~,这边要花时间自己看一下,看懂就会发现其实这原理很简单,但查位置真的挺花时间的。
再来就是要去main.c里去赋予值给这些暂存器瞜,首先天上我的程序码:

//main.c
#include "stm32f103.h" 
int main(void)
{	
	int i=0;
	RCC_APB2ENR |= (1<<2);//开GPIOA的时钟
	
	GPIOA_CRL	&= ~( 0xf<< (4)); //对要使用位置清0
	GPIOA_CRL	|= ( 0x1<< (4));  //赋予值

	while(1)
	{
		GPIOA_BSRR	|= ( 1<< 1); //GPIOA Pin1_Hi,开发版上的A1脚位
		for(i=0;i<=480000;i++)
		{
		}	
		i=0;
		GPIOA_BSRR	|= ~( 1<< 1);//GPIOA Pin1_LOW,开发版上的A1脚位
		for(i=0;i<=480000;i++)
		{
		}	
	}
}
//打这个函式是为了让编译器不报错,实际的原因是.s启动档那有宣告执行这函式
//,所以让他实现空空的的函示就好
void SystemInit(void)
{	
}

我这边就当作大家都懂c语言跟基本的数位逻辑观念了,不懂的话再去搜寻一下吧。
首先RCC开启时钟的部份
https://ithelp.ithome.com.tw/upload/images/20210918/20141979ywSQwOvQx8.png
可以看到上图我红框部份,再去对应我main.c的开启时钟看,到这边看懂的话你就会操作了~
RCC_APB2ENR |= (1<<2); 讲解一下这行,1左移两位(1 => 100)或上RCC_APB2ENR这个暂存器。就这样,这个不会的话要去看一下基本数位逻辑喔

下面程序我就不解释,一样的道理,去查看CRL和BSRR暂存器就可以啦,CRL主要是在配置IO口模式,我用简单计数来当delay,BSRR一边控制HI,一边控制LOW,完成啦
验证过了可以动作~,这套查询的方式套用到哪颗MCU都可以!,方法都一样
讲一下烧录的方式
https://ithelp.ithome.com.tw/upload/images/20210918/20141979RnGINrQMx9.png
确定编译没错才能烧录喔,烧入後记得按Reset,把LED接到 A1 的脚位就会看到LED在闪烁了喔~

底层就是这样动作了,有什麽问题可以在下面提出来~
我预计明天来讲暂存器的查找方式吧


<<:  【4】实验 Batch size大小对训练模型的影响

>>:  [Day9] 实作 - 主角篇4

Day 30:赛後感言

这其实是有点长的故事,但我觉得这种缘分有点有趣,所以就决定在最後一天整理一下。 从开赛前几天说起 在...

【後转前要多久】# Day20 BootStrap - 通用类别 Utilities

今天要来介绍 Bootstrap 工具、通用类别 在这章节中,最重要的就是要熟悉各种装置尺寸代号, ...

RISC-V on Rust 从零开始(9) - 实作memory model

CPU指令可以分成两大类,一是操作CPU内部暂存器的算术逻辑指令,一是存取记忆体,也就是所谓的loa...

JavaFX+SceneBuliider+jfoneix +eclipse 安装

1.安装JavaFX 首先去GLUON官网下载 JavaFX Windows x64 SDK 版本的...

结语

结语 目前完成进度 登入 登出 朋友的邀请与拒绝和同意 新增聊天室 新增讯息 尚未完成 讯息显示 未...