[STM32F1] STM32F103(一)使用寄存器控制LED灯

[复制链接]
 楼主| 自动化陈稳 发表于 2021-4-26 22:04 | 显示全部楼层 |阅读模式
一、使用寄存器控制LED灯一、LED电路原理

如下图,右侧为3.3V高电平电压,左侧对应PB5等,一共三个端口,对应三种颜色LED灯,要想让灯亮,即让对应端口输出0V电压,这样就产生了由右向左的3.3V压降。

704176086c8809ba6b.png


 楼主| 自动化陈稳 发表于 2021-4-26 22:06 | 显示全部楼层
二、如何输出端口值
如下图ODR寄存说明,以点亮绿灯为例,该端口为低16位有效,PB0端口需要输出为0,此处给出偏移地址为0Ch,而查阅手册得知GPIO的B端口物理地址为0x40010C00,所以要想点亮绿灯,要控制rw0位为0,其真实地址即为0x40010C0C即代码
 楼主| 自动化陈稳 发表于 2021-4-26 22:06 | 显示全部楼层
  1. *(unsigned int *)0x40010C0C &=~(1<<0);
 楼主| 自动化陈稳 发表于 2021-4-26 22:07 | 显示全部楼层
此处第一个*表示改变0x40010C0C地址的内存
unsigned int *表示强制改变0x40010C0C为指针类型,
&是与运算
~是取反运算
(1<<0)表示1左移0位
所以即为0左移0位,与原来的低16位相与,只有rw0位变为0,其余位不变,这也是常用的清零操作。
 楼主| 自动化陈稳 发表于 2021-4-26 22:08 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2021-4-26 22:08 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2021-4-26 22:09 | 显示全部楼层
三、如何使端口模式为输出模式
下面是CRL寄存器的原理介绍,为32位,每四位对应ODR中的1位,所以对于PB0来说,就是CRL中的0123四位控制,要想使PB0端口为输出电压模式,要将CNF置为00,MODE置为01,偏移地址为0x00,实际地址即为0x40010C00,代码如下:
 楼主| 自动化陈稳 发表于 2021-4-26 22:09 | 显示全部楼层
//配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
        *(unsigned int *)0x40010C00 |=((1)<<(4*0));

这里的 | 是或运算,只有目标位与1相或,所得结果均为1,其余位均不变。
 楼主| 自动化陈稳 发表于 2021-4-26 22:10 | 显示全部楼层
 楼主| 自动化陈稳 发表于 2021-4-26 22:11 | 显示全部楼层
四、如何打开端口时钟控制
在RCC中,如下图,PB端口是第3位控制
19516086c9f67c874.png
 楼主| 自动化陈稳 发表于 2021-4-26 22:12 | 显示全部楼层
找到第三位对于IOPB时钟的说明如下
780896086ca40b8a4f.png
 楼主| 自动化陈稳 发表于 2021-4-26 22:13 | 显示全部楼层
所以在RCC寄存器中,第3位的值要置1,才能开启B时钟,端口才能正常工作,上面已经查到RCC的物理地址为0x40021000,偏移地址为0x18,实际地址即为0x40021018,
打开时钟的代码如下
*(unsigned int *)0x40021018 |=((1)<<3);
 楼主| 自动化陈稳 发表于 2021-4-26 22:13 | 显示全部楼层
五、延时代码
这个就很简单了,一个for循环搞定
void delay(unsigned int i)
{
        unsigned int j=0;
        for(j=0;j<=i;j++)
        {}
}
 楼主| 自动化陈稳 发表于 2021-4-26 22:14 | 显示全部楼层
六、其它注意事项
在main函数中,用while循环,每点亮一个灯后延时一段时间,再改变CRL,使端口模式为输入,就关闭该灯了,再打开另外颜色的灯,以此类推,改变CRL代码为:
  1.         *(unsigned int *)0x40010C00 &=~((15)<<(4*0));
 楼主| 自动化陈稳 发表于 2021-4-26 22:15 | 显示全部楼层
这里的十进制15对应二进制的1111,

整个程序的完整代码如下:
  1. #include "stm32f10x.h"

  2. void delay(unsigned int i)
  3. {
  4.         unsigned int j=0;
  5.         for(j=0;j<=i;j++)
  6.         {}
  7. }

  8. int main(void)
  9. {
  10.         //PB5 0 1对应R G B
  11.        
  12.         while(1)
  13.         {
  14.         //打开GPIOB端口的时钟(绿色)
  15.         *(unsigned int *)0x40021018 |=((1)<<3);
  16.         //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
  17.         *(unsigned int *)0x40010C00 |=((1)<<(4*0));
  18.         //控制ODR寄存器,ODR偏移地址为0C
  19.         *(unsigned int *)0x40010C0C &=~(1<<0);
  20.         delay(500000);
  21.         *(unsigned int *)0x40010C00 &=~((15)<<(4*0));
  22.           
  23.          
  24.         //打开GPIOB端口的时钟(蓝色)
  25.         *(unsigned int *)0x40021018 |=((1)<<3);
  26.         //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
  27.         *(unsigned int *)0x40010C00 |=((1)<<(4*1));
  28.         //控制ODR寄存器,ODR偏移地址为0C
  29.         *(unsigned int *)0x40010C0C &=~(1<<1);
  30.         delay(500000);
  31.         *(unsigned int *)0x40010C00 &=~((15)<<(4*1));
  32.        
  33.                
  34.         //打开GPIOB端口的时钟(红色)
  35.         *(unsigned int *)0x40021018 |=((1)<<3);
  36.         //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
  37.         *(unsigned int *)0x40010C00 |=((1)<<(4*5));
  38.         //控制ODR寄存器,ODR偏移地址为0C
  39.         *(unsigned int *)0x40010C0C &=~(1<<5);
  40.         delay(500000);
  41.         *(unsigned int *)0x40010C00 &=~((15)<<(4*5));
  42.        
  43.        
  44.         }
  45. }



  46. void SystemInit(void)
  47. {
  48.         //函数体为空,没有用库函数,为了不报错
  49. }
coshi 发表于 2021-5-11 20:44 | 显示全部楼层
电路原理还是很简单的
zljiu 发表于 2021-5-11 20:44 | 显示全部楼层
电阻应该根据什么来计算呢
wiba 发表于 2021-5-11 20:44 | 显示全部楼层
为什么是不同的电阻呢
tfqi 发表于 2021-5-11 20:45 | 显示全部楼层
非常不错的想法啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

105

主题

1379

帖子

1

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