打印
[STM32F1]

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

[复制链接]
520|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一、使用寄存器控制LED灯一、LED电路原理

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


使用特权

评论回复
沙发
自动化陈稳|  楼主 | 2021-4-26 22:06 | 只看该作者
二、如何输出端口值
如下图ODR寄存说明,以点亮绿灯为例,该端口为低16位有效,PB0端口需要输出为0,此处给出偏移地址为0Ch,而查阅手册得知GPIO的B端口物理地址为0x40010C00,所以要想点亮绿灯,要控制rw0位为0,其真实地址即为0x40010C0C即代码

使用特权

评论回复
板凳
自动化陈稳|  楼主 | 2021-4-26 22:06 | 只看该作者
*(unsigned int *)0x40010C0C &=~(1<<0);

使用特权

评论回复
地板
自动化陈稳|  楼主 | 2021-4-26 22:07 | 只看该作者
此处第一个*表示改变0x40010C0C地址的内存
unsigned int *表示强制改变0x40010C0C为指针类型,
&是与运算
~是取反运算
(1<<0)表示1左移0位
所以即为0左移0位,与原来的低16位相与,只有rw0位变为0,其余位不变,这也是常用的清零操作。

使用特权

评论回复
5
自动化陈稳|  楼主 | 2021-4-26 22:08 | 只看该作者

使用特权

评论回复
6
自动化陈稳|  楼主 | 2021-4-26 22:08 | 只看该作者

使用特权

评论回复
7
自动化陈稳|  楼主 | 2021-4-26 22:09 | 只看该作者
三、如何使端口模式为输出模式
下面是CRL寄存器的原理介绍,为32位,每四位对应ODR中的1位,所以对于PB0来说,就是CRL中的0123四位控制,要想使PB0端口为输出电压模式,要将CNF置为00,MODE置为01,偏移地址为0x00,实际地址即为0x40010C00,代码如下:

使用特权

评论回复
8
自动化陈稳|  楼主 | 2021-4-26 22:09 | 只看该作者
//配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
        *(unsigned int *)0x40010C00 |=((1)<<(4*0));

这里的 | 是或运算,只有目标位与1相或,所得结果均为1,其余位均不变。

使用特权

评论回复
9
自动化陈稳|  楼主 | 2021-4-26 22:10 | 只看该作者

使用特权

评论回复
10
自动化陈稳|  楼主 | 2021-4-26 22:11 | 只看该作者
四、如何打开端口时钟控制
在RCC中,如下图,PB端口是第3位控制

使用特权

评论回复
11
自动化陈稳|  楼主 | 2021-4-26 22:12 | 只看该作者
找到第三位对于IOPB时钟的说明如下

使用特权

评论回复
12
自动化陈稳|  楼主 | 2021-4-26 22:13 | 只看该作者
所以在RCC寄存器中,第3位的值要置1,才能开启B时钟,端口才能正常工作,上面已经查到RCC的物理地址为0x40021000,偏移地址为0x18,实际地址即为0x40021018,
打开时钟的代码如下
*(unsigned int *)0x40021018 |=((1)<<3);

使用特权

评论回复
13
自动化陈稳|  楼主 | 2021-4-26 22:13 | 只看该作者
五、延时代码
这个就很简单了,一个for循环搞定
void delay(unsigned int i)
{
        unsigned int j=0;
        for(j=0;j<=i;j++)
        {}
}

使用特权

评论回复
14
自动化陈稳|  楼主 | 2021-4-26 22:14 | 只看该作者
六、其它注意事项
在main函数中,用while循环,每点亮一个灯后延时一段时间,再改变CRL,使端口模式为输入,就关闭该灯了,再打开另外颜色的灯,以此类推,改变CRL代码为:
        *(unsigned int *)0x40010C00 &=~((15)<<(4*0));

使用特权

评论回复
15
自动化陈稳|  楼主 | 2021-4-26 22:15 | 只看该作者
这里的十进制15对应二进制的1111,

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

void delay(unsigned int i)
{
        unsigned int j=0;
        for(j=0;j<=i;j++)
        {}
}

int main(void)
{
        //PB5 0 1对应R G B
       
        while(1)
        {
        //打开GPIOB端口的时钟(绿色)
        *(unsigned int *)0x40021018 |=((1)<<3);
        //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
        *(unsigned int *)0x40010C00 |=((1)<<(4*0));
        //控制ODR寄存器,ODR偏移地址为0C
        *(unsigned int *)0x40010C0C &=~(1<<0);
        delay(500000);
        *(unsigned int *)0x40010C00 &=~((15)<<(4*0));
          
         
        //打开GPIOB端口的时钟(蓝色)
        *(unsigned int *)0x40021018 |=((1)<<3);
        //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
        *(unsigned int *)0x40010C00 |=((1)<<(4*1));
        //控制ODR寄存器,ODR偏移地址为0C
        *(unsigned int *)0x40010C0C &=~(1<<1);
        delay(500000);
        *(unsigned int *)0x40010C00 &=~((15)<<(4*1));
       
               
        //打开GPIOB端口的时钟(红色)
        *(unsigned int *)0x40021018 |=((1)<<3);
        //配置IO口为输出,CRL端口偏移地址为00,十进制的1,即为0001,左移0位
        *(unsigned int *)0x40010C00 |=((1)<<(4*5));
        //控制ODR寄存器,ODR偏移地址为0C
        *(unsigned int *)0x40010C0C &=~(1<<5);
        delay(500000);
        *(unsigned int *)0x40010C00 &=~((15)<<(4*5));
       
       
        }
}



void SystemInit(void)
{
        //函数体为空,没有用库函数,为了不报错
}

使用特权

评论回复
16
coshi| | 2021-5-11 20:44 | 只看该作者
电路原理还是很简单的

使用特权

评论回复
17
zljiu| | 2021-5-11 20:44 | 只看该作者
电阻应该根据什么来计算呢

使用特权

评论回复
18
wiba| | 2021-5-11 20:44 | 只看该作者
为什么是不同的电阻呢

使用特权

评论回复
19
tfqi| | 2021-5-11 20:45 | 只看该作者
非常不错的想法啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

72

主题

1182

帖子

1

粉丝