纯寄存器开发方式使用STM32C8T6芯片点亮LED

# 废话不多说,先总结流程

1. 先下载官方的库文件,这一步只是为了拿到官方写好的启动文件,不然手写启动文件太麻烦了

2. 有了启动文件就可以直接写main函数了,所以我们第二部创建Keil的工程

3. 然后就是查手册并写代码,烧入程序运行查看结果

## 下载官方库文件

在ST官网的软件菜单中找到STM32标准外设软件库:

这部分不懂可以看:

STM32标准外设库(标准库)官网下载方法,附带2021最新标准固件库下载链接_stm32标准库官网-CSDN博客

## 在Keil中新建工程

这部分也就要注意芯片型号选对,没有芯片信号就是没装pack包,可以看这个:

STM32芯片包下载和安装教程-CSDN博客

新建完成工程之后,应该是啥文件都没有的,这个时候需要搞两个文件:

1. 启动文件:这个来自于刚才下载的压缩包里,要注意的是,型号要选对,都是STM32F103,也有大中小容量的分别,导致启动文件不一样,这个不懂可以看:

STM32的启动文件的选择(由容量大小决定)_keil 不同容量单片机怎么选启动文件-CSDN博客

STM32不同型号的芯片对应的启动文件如何选择_startup_stm32f10x_cl-CSDN博客

2. 自己新建一个main.c文件,用来待会儿写代码

补充:启动文件是单片机上电后第一个运行的文件,并且是用汇编写的,里面主要是对堆栈、中断向量表之类的很底层的东西进行初始化,最后进入到C语言的环境,也就是启动文件运行完成了才能跑C语言代码。初学阶段不太需要了解,但是工程大了变量多了,堆栈不够用了是需要修改启动文件的,所以以后还是要学的(启动文件代码也不多),有关于启动文件的分析,可以看下这个:

15. 启动文件详解 — [野火]STM32库开发实战指南——基于野火MINI开发板 文档

我使用的C8T6是64kb的中容量版本,所以启动文件选取hd.s

然后写下main函数并编译:(有报错)

这个是由于汇编文件中调用了SystemInit函数,但是没有定义:

解决办法:写个空函数,让他能够调用不报错就行(严谨的讲,一些操作并没有完成)

到这里反正编译过了,就不用管了。

## 最后编写代码

### 知识储备

核心:(这个是最重点的内容,虽然我说的不准确,但是也请你记下来)

1. 对单片机编程,就是在操作寄存器,无非就是对寄存器进行 读取 和 写入 。(告诉你你要干什么)

2. 寄存器不只是存储器,是连接了硬件的,对寄存器的 读取 和 写入 就会间接影响硬件的工作状态。(解释为什么要这么干)

3. 寄存器在冯诺依曼的架构中,不过就是内存中间的某一部分。所以想要访问寄存器,就理解为访问内存就好了,所以在C语言里面,就是用指针访问。(告诉你该怎么干)

而对于本次的点灯操作,就是要控制一个硬件(GPIO的引脚,就是芯片引脚),改变他的工作状态(修改输出模式并修改成输出低电平)。

但是这里需要注意的是,在STM32的结构里,GPIO是一个挂载在APB2总线上面的外设,所以我们要对GPIO进行操作,先要把APB2总线打开,才能通过 CPU --》 APB2总线 --》 GPIO 这条通路进行操作。所以我们可以得到以下的操作步骤:

1. 打开APB2上面的GPIO通路的时钟(让通路的中间部分打通)

2. 配置GPIO的模式,初始化

3. 修改GPIO的引脚输出电压

这里再补充一点我的心得:

对于任何的外设,不论是哪一个,你只需要学习两个或者三个操作即可:

1. 对这个外设初始化

2. 对这个外设进行 读取 或者 写入 或者 读取和写入 这些操作就够了

比如,你想学UART,不就是学会了初始化、发送数据、接收数据三个操作就够了吗?(这里只是说驱动层面,通讯协议之类的是上层了,那些就不是单片机自身的知识点了)

再比如,你想学ADC不就是,初始化 + 读取ADC的测量值 两个操作就够了吗?

最后看这个总结,接下来就可以写代码了:

寄存器修改的代码怎么写:

 *(unsigned int * )( 基础地址 + 偏移地址 ) = 你想修改的值;

稍微解释一下:

        首先,STM32把内存像是切蛋糕一样先切出了几个大块,每一块都是一个的外设的所有寄存器。这就是为什么有 基础地址 ,就好像先告诉你你要找的人在哪条街道。

        其次,在一块里面,也有好多寄存器,对吧,然后你要找到某一寄存器,就要通过 偏移地址 。就好像是,找到街道之后告诉你,你要找到人在这条街道的第几个房子里。

        最后,地址是找到了,我们要对地址下的值进行修改所以,我们会写出 ( * 地址 = 值 )  这样子的代码,但是这个样子会报错。因为我们这里的 地址 在编译器看来,是一个常数,你怎么可以对常数进行解引用呢?所以我们还用一个强制类型转换( unsigned int * ),这里unsigned是必须有的,因为寄存器地址就是0开始的,没有负数。int是指明这个地址是32位的,因为STM32就是32位的。

好的,有了以上的这些知识储备,就可以知道该怎么写代码了。

(二次修改添加的内容)

如何读写单个寄存器的值:

(假设对一个8位寄存器进行操作,每次都是操作第5位)

情况1:不修改其他寄存器的值,把某一位置1:

用按位或来置1:

        * (unsigned char *)(地址)  |= (1 << 5) ;

情况2:某一位置清0

用按位与来清0:

        * (unsigned char *)(地址)  &= ~(1 << 5) ;        // 注意要取反

情况3:读取某一位置的值

用按位与配合if语句:

        if ( * (unsigned char *)(地址)  & (1 << 5) ) {

                // 运行到这里说明这个位是1

        } else {

                // 运行到这里说明这个位是0

        }

### 实操

0. 首先声明,我的开发板的LED是接到GPIO_C 13端口的,并且是低电平驱动。

然后手册是:STM32F103的中文手册,寄存器手册。

1. 先开启APB2的GPIOC的时钟:

1.1 查询基地址(这个要在手册的寄存器映射部分找!)

1.2 然后找偏移地址:

1.3 分析一下要写什么数据进去:

(一般EN就是使能,就是写1打开,写0关闭;这个是我的经验,所以就不用看下面的手册对于值的解释了,下面的模式选择再带你们看)

因为手册上写的是第4位是GPIO-C的时钟,所以给1的值是1 0000b = 0x10 (二进制转16进制)

1.4 代码:(数字内的空格记得删掉,我这么些是为了易读)

*(unsigned int *) (0x4002 1000 + 0x18) |= 0x10;

 2. 然后如法炮制,写GPIO C的模式选择。

2.1 GPIO C的基础地址:(在寄存器映射部分找)

2.2 模式寄存器的偏移地址:(这个在GPIO外设部分找)

2.3 最后是看下这些寄存器要给什么值:

(这张图片和上一张图片在手册里其实是连着的,所有的寄存器手册都是这个结构)

查手册可以知道我们要把GPIO设置成输出模式,且最好是推挽输出模式:则寄存器的值设置为:第23位是0,第22位是0,第21位是1,第20位是0,则对应的16进制代码是:0x0020 0000

2.4 最后写代码:(数字内的空格记得删掉,我这么些是为了易读)

*(unsigned int *)(0x4001 1000 + 0x04) = 0x0020 0000;

3. 最后是让端口输出低电平

3.1 因为我们还是操作GPIO—C端口,所以基地址肯定没变,不用查了

3.2 然后查询偏移地址:

3.3 最后查要写入的值,可以看到上图里面已经有了,就是写1是高电平,写0是低电平。

        然后这里补充一点点,仔细看手册,开头是GPIOx_ORD这里x是小写的!意味着x是A或者是B或者是C...那么我们怎么区分呢?或者说,为啥我这里操作就是在改GPIO_C而不是在改GPIO_A呢?因为基地址我们写的就是GPIO_C了,加上偏移地址,肯定是GPIO_C的输出寄存器。如果我们基地址选择的是GPIO_D,然后加上这里的偏移地址,那不就是操作GPIO_D吗。所以由此我们还可以看出,GPIO_A和GPIO_B和...的内部寄存器结构是一样的,就好像是两排完全一样的学生宿舍的结构。

        第二个要补充的是,请注意偏移地址之下,还有一个默认值!这个东西也挺重要的,学习过STM32时钟树相关知识的同学肯定知道时钟对于芯片的重要性,肯定会有人问,我芯片时钟都没配置芯片怎么能跑的起来的,就是因为默认值给我们的芯片接上了内部的时钟,所以虽然我们没有配置时钟,但是芯片的默认值已经帮我们配置了一个时钟。(但是速率不怎么样,实际使用时我们还是要手动配置到外部晶振的)而在这里,由于默认值就是0,也就是输出低电平,所以其实这一行代码我们不写,灯也还是能被点亮的。

3.4 所以代码是:

*(unsigned int *)(0x4001 1000 + 0x0C) = 0x0000;

4 代码写完了,编译并且烧录,看结果

4.1 完整代码预览:

void SystemInit(void);         // 汇编文件里调用的函数的声明
void SystemInit(void){}        // 函数定义

#define RCC_BASE 0x40021000    // 手册查到的基础地址
#define GPIOC_BASE 0x40011000  // 手册查到的基础地质
int main()
{
	// APB2外设时钟寄存器配置,开启GPIO-C的时钟
	*(unsigned int *)(0x40021000 + 0x18) |= 0x10;
	
	// 配置引脚模式为输出模式
	*(unsigned int *)(0x40011000 + 0x04) |= 0x00200000;
	
	// GPIO-C 13引脚的输出电平置低
	*(unsigned int *)(0x40011000 + 0x0C) = 0x0;
	
	while(1);	// 防止程序结束
}

// by likeszm

4.2 编译和下载程序:

你要先配置好ST-Link,这个你可以看:

STM32学习笔记3:KEIL5中使用ST-Link烧录调试STM32芯片的步骤_keil5使用stlink-CSDN博客

stm32 stlink 烧录 keil5配置 - 知乎

下载完成之后应该会在输出窗口显示类似这些东西:

4.3 现象:程序下载完成之后也不一定会立马有现象,可以按一下重启键,让芯片从头开始跑代码

最后提醒一句,本文所有的重点思想都是块引用内的文字,希望各位细细体会。

就是这种文本框内的文字啦。

by 李科笙不写作业

完结撒花

  • 17
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值