[其他ST产品] stm32-寄存器点灯

[复制链接]
1408|28
 楼主| 个百zz分点个 发表于 2023-11-29 12:30 | 显示全部楼层 |阅读模式
对于stm32通常有三种编程方式对其进行控制,分别是寄存器、库函数、HAL库。其中库函数用的最多,但是对于新手,使用寄存器的方式能更好地学习单片机内部的结构以及运行过程。

本文就是基于寄存器方式实现简单的点灯操作。

一、常用寄存器
对于每个寄存器都有一段分配的地址,我们只需要找到需要使用到地址,对其进行赋值等操作,就可以实现我们想要的结果。

根据STM32F103中文教程及参考手册,我们就可以得到每个寄存器对应的起始地址,对起始地址进行加减可以得到我们想要控制的端口。

1、RCC寄存器
2、GPIO寄存器
(1)端口配置低寄存器GPIOX_CRL
每个GPIOX都要16个输入、输出端口,即PX0-PX15,而GPIO_CRL则控制的是PX0-PX7,GPIO_CRH控制的是PX8-PX15。 877096566be71630c5.png

 楼主| 个百zz分点个 发表于 2023-11-29 12:31 | 显示全部楼层
每四位控制一个端口,因此,用十六进制数刚好能够描述每一位的状况。这里所说的状况就是输入输出模式。

362076566be7f5be1d.png
每四位中的高两位控制输出模式,低两位控制输出速度,因此由四位控制整个端口输出。
 楼主| 个百zz分点个 发表于 2023-11-29 12:31 | 显示全部楼层
(2)端口配置高寄存器GPIOX_CRH
775646566be94a49ff.png
 楼主| 个百zz分点个 发表于 2023-11-29 12:43 | 显示全部楼层
(3)端口输入数据寄存器GPIOX_IDR
72296566c163c9154.png
IDR和ODR均能对数据进行存储。但是IDR是对输入数据进行存储,ODR是对输出数据进行存储。

高十六位始终为零,只用低十六位存储十六个输入输出引脚的数据。
 楼主| 个百zz分点个 发表于 2023-11-29 12:43 | 显示全部楼层
(4)端口输出数据寄存器GPIOX_ODR、
139156566c18706341.png
 楼主| 个百zz分点个 发表于 2023-11-29 12:44 | 显示全部楼层
3.输出模式
229216566c19764c3a.png

输出模式由红色方框中的器件进行控制。

(1)推挽输出
推挽输出时,P-MOS有效、N-MOS无效。高低电平均能输出。

(2)开漏输出
开楼输出时,P-MOS无效、N-MOS有效。只能输出低电平,不能输出高电平。
 楼主| 个百zz分点个 发表于 2023-11-29 12:44 | 显示全部楼层
二、点亮LED
绝对地址=外设基地址+偏移地址

这里的外设基地址也就是外设的初始地址。

本文设计了三个led,接入引脚分别为PA0、PB0、PC15,控制led灯的亮灭,其实就是控制对应I/O口的高低电平。

通常有以下三个步骤:

1、配置时钟寄存器RCC
446396566c1c61f577.png
 楼主| 个百zz分点个 发表于 2023-11-29 12:45 | 显示全部楼层
根据该系统结构图,如果我们要对GPIOX进行控制输出,我们就需要让APB2工作,因此,在配置时钟时,我们选用的时APB2外设时钟使能寄存器

427656566c1d7bba1e.png

598296566c1de12c17.png
 楼主| 个百zz分点个 发表于 2023-11-29 12:45 | 显示全部楼层
由此,计算出该寄存器的绝对地址=0x40021000+0x18=0x4002018
400216566c1ee87ef9.png
 楼主| 个百zz分点个 发表于 2023-11-29 12:45 | 显示全部楼层
根据上图,我们需要将选用的GPIOA、GPIOB、GPIOC 的时钟均开启,开启之后才能进行工作,因此就需要将位2、位3、位4置1,代码如下:

//配置复位和时钟控制寄存器(RCC)-使能寄存器APB2
        *(unsigned int*)0x40021018|=(0X7<<2);//7的二进制位111
 楼主| 个百zz分点个 发表于 2023-11-29 12:58 | 显示全部楼层
2、配置输出模式-推挽输出
点亮led灯只需要输出高低电平就能实现led的亮与灭,需要对输出数据进行存储,因此应该将CRL或者CRH设置为推挽模式

764776566c4f658278.png

本文采用的是输出最大速度为50MHz的推挽输出模式,因此二进制表示为0011,转化为十六进制为3。
 楼主| 个百zz分点个 发表于 2023-11-29 13:02 | 显示全部楼层
又因为本文接入引脚分别为PA0、PB0、PC15,所以分别将对应的GPIOX的位0、位0、位15设置为3即可。
690696566c5e019c13.png
代码为:

//配置为推挽输出
//初始地址GPIOA:0x40010800、GPIOB:0x40010C00、GPIOC:0x40011000
        *(unsigned int*)0x40010800|=0x00000003;//PA0,低位,偏移地址0x00
        *(unsigned int*)0x40010C00|=0x00000003;//PB0,低位,偏移地址0x00
        *(unsigned int*)0x40011004|=0x30000000;//PC15,高位,偏移0x04
 楼主| 个百zz分点个 发表于 2023-11-29 13:10 | 显示全部楼层
3、配置端口输出数据寄存器
低电平点亮、高电平熄灭。

代码为:
  1. //全亮
  2.                         *(unsigned int*)0x4001080C&=~(0x0);
  3.                         *(unsigned int*)0x40010C0C&=~(0x0);
  4.                         *(unsigned int*)0x4001100C&=~(0x0<<15);
  5.                         delay();
  6. //AB亮,C灭
  7.                         *(unsigned int*)0x4001080C&=~(0x0);
  8.                         *(unsigned int*)0x40010C0C&=~(0x0);
  9.                         *(unsigned int*)0x4001100C=0x1<<15;
  10.                 delay();
  11. //A亮,BC灭
  12.                         *(unsigned int*)0x4001080C&=~(0x0);
  13.                         *(unsigned int*)0x40010C0C=0x1<<0;
  14.                         *(unsigned int*)0x4001100C=0x1<<15;
  15.                 delay();
  16. //ABC全灭
  17.                         *(unsigned int*)0x4001080C=0x1;
  18.                         *(unsigned int*)0x40010C0C=0x1;
  19.                         *(unsigned int*)0x4001100C=0x1<<15;
  20.                 delay();
 楼主| 个百zz分点个 发表于 2023-11-29 13:10 | 显示全部楼层
4.最终代码

  1. #include "stm32f10x.h"                  // Device header

  2. //延时
  3. void delay()
  4. {
  5.         int i,j;
  6.         for (i=0;i<100000;i++)
  7.         for (j=0;j<100;j++);
  8. }
  9. void led()
  10. {
  11.        
  12. }
  13. int main(void)
  14. {
  15.         //初始地址GPIOA:0x40010800、GPIOB:0x40010C00、GPIOC:0x40011000
  16.         // &= ~用来清0(给某一位单独置0)
  17.         // |= 用来给某一位单独置1
  18.         //配置复位和时钟控制寄存器(RCC)-使能寄存器APB2
  19.         *(unsigned int*)0x40021018|=(0X7<<2);
  20.         //配置为推挽输出
  21.         *(unsigned int*)0x40010800|=0x00000003;//PA0,低位,偏移地址0x00
  22.         *(unsigned int*)0x40010C00|=0x00000003;//PB0,低位,偏移地址0x00
  23.         *(unsigned int*)0x40011004|=0x30000000;//PC15,高位,偏移0x04
  24.         //配置端口输出数据寄存器ODR,偏移地址0x0Ch
  25.         while(1)
  26.         {
  27.                
  28.                 //全亮
  29.                         *(unsigned int*)0x4001080C&=~(0x0);
  30.                         *(unsigned int*)0x40010C0C&=~(0x0);
  31.                         *(unsigned int*)0x4001100C&=~(0x0<<15);
  32.                         delay();
  33.           //AB亮,C灭
  34.                         *(unsigned int*)0x4001080C&=~(0x0);
  35.                         *(unsigned int*)0x40010C0C&=~(0x0);
  36.                         *(unsigned int*)0x4001100C=0x1<<15;
  37.                 delay();
  38.                 //A亮,BC灭
  39.                         *(unsigned int*)0x4001080C&=~(0x0);
  40.                         *(unsigned int*)0x40010C0C=0x1<<0;
  41.                         *(unsigned int*)0x4001100C=0x1<<15;
  42.                 delay();
  43.                 //ABC全灭
  44.                         *(unsigned int*)0x4001080C=0x1;
  45.                         *(unsigned int*)0x40010C0C=0x1;
  46.                         *(unsigned int*)0x4001100C=0x1<<15;
  47.                 delay();
  48.         }
  49. }
 楼主| 个百zz分点个 发表于 2023-11-29 13:11 | 显示全部楼层
5、仿真结果
191756566c7f717cdd.png
 楼主| 个百zz分点个 发表于 2023-11-29 13:11 | 显示全部楼层
6、烧录结果
150156566c80f49370.png
 楼主| 个百zz分点个 发表于 2023-11-29 13:12 | 显示全部楼层
三、补充
由于STM32最小系统核心板子出厂时已经焊接好了1个led灯(标注了PC13处),一般可通过此灯的点亮让编程者验证自己烧录的代码是否正常运行了。下面是将这个灯也用在流水灯中,进行点灯。在代码中只需要将位移15的地方改为13、以及推挽输出的位置。
 楼主| 个百zz分点个 发表于 2023-11-29 13:12 | 显示全部楼层
最终代码如下:
  1. #include "stm32f10x.h"                  // Device header

  2. //延时
  3. void delay()
  4. {
  5.         int i,j;
  6.         for (i=0;i<100000;i++)
  7.         for (j=0;j<100;j++);
  8. }
  9. void led()
  10. {
  11.        
  12. }
  13. int main(void)
  14. {
  15.         //初始地址GPIOA:0x40010800、GPIOB:0x40010C00、GPIOC:0x40011000
  16.         // &= ~用来清0(给某一位单独置0)
  17.         // |= 用来给某一位单独置1
  18.         //配置复位和时钟控制寄存器(RCC)-使能寄存器APB2
  19.         *(unsigned int*)0x40021018|=(0X7<<2);
  20.         //配置为推挽输出
  21.         *(unsigned int*)0x40010800|=0x00000003;//PA0,低位,偏移地址0x00
  22.         *(unsigned int*)0x40010C00|=0x00000003;//PB0,低位,偏移地址0x00
  23.         *(unsigned int*)0x40011004|=0x00300000;//PC13,高位,偏移0x04
  24.         //配置端口输出数据寄存器ODR,偏移地址0x0Ch
  25.         while(1)
  26.         {
  27.                
  28.                 //全亮
  29.                         *(unsigned int*)0x4001080C&=~(0x0);
  30.                         *(unsigned int*)0x40010C0C&=~(0x0);
  31.                         *(unsigned int*)0x4001100C&=~(0x0<<13);
  32.                         delay();
  33.           //AB亮,C灭
  34.                         *(unsigned int*)0x4001080C&=~(0x0);
  35.                         *(unsigned int*)0x40010C0C&=~(0x0);
  36.                         *(unsigned int*)0x4001100C=0x1<<13;
  37.                 delay();
  38.                 //A亮,BC灭
  39.                         *(unsigned int*)0x4001080C&=~(0x0);
  40.                         *(unsigned int*)0x40010C0C=0x1<<0;
  41.                         *(unsigned int*)0x4001100C=0x1<<13;
  42.                 delay();
  43.                 //ABC全灭
  44.                         *(unsigned int*)0x4001080C=0x1;
  45.                         *(unsigned int*)0x40010C0C=0x1;
  46.                         *(unsigned int*)0x4001100C=0x1<<13;
  47.                 delay();
  48.         }
  49. }
 楼主| 个百zz分点个 发表于 2023-11-29 13:12 | 显示全部楼层
烧录实现如下:
739356566c83f0b703.png
Stahan 发表于 2023-11-29 16:09 | 显示全部楼层
寄存器操作起来好麻烦啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

53

主题

679

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部