day04:点亮一个LED
=========== 以下步骤比较繁琐,请参考 http://www.cnblogs.com/josephcnblog/articles/8846801.html
(1)查看STM32原理图:比如要点亮D4这个LED,它的阳极(+)接在3V3的高电平,所以要点亮这个LED,就要让它的阴极(-)输出低电平(0V)。

PC2表示输出端口号。D4表示LED灯别名。
(2)查看STM32F10X中文手册
看GPIO寄存器:

因为LED端口号是PC2,表示第三个端口(端口从0开始)。高16位保留(用户不能操作),第十六位可设置。
先来理解一个位运算的知识:

所以,要将第三位清零,只需要把它的地址指针的值进行 &= ~ 位运算即可。
而单片机中用的是内存地址,而C中用的是指针,这两者是对应的。
但是只有地址偏移,没有真正的内存地址,真正地址 = 起始地址 + 地址偏移,而寄存器是有特殊功能的内存单元,给单元分配内存地址就是映射过程,

所以查找“存储器映射”资料:

查看第三个端口,即C端口,它的起始地址是:0X4001 1000,加上地址偏移 0Ch,即C,结果是:0X4001 100C
所以,配置ODR寄存器是: *(unsigned int *)0X4001100C &= ~(1<<2),下面解释这句代码:看下面的解释就懂

1 ============================================== 编译代码,烧录到单片机
#include "stm32f10x.h"
int main(void)
{
/* 配置ODR寄存器 */
*(unsigned int *)0X4001100C &= ~(1<<2);
while(1);
}
点这个图片,将文件输出成 .hex 文件,这个格式文件是可以通过串口烧录到单片机中的


重新编译,点下面的图标:烧录到单片机

打开mcuisp.exe串口程序下载工具:

点击“Build”生成 .hex 文件,报错:缺少。。。。。。。。。.axf 文件,这是因为没有在开发环境中添加GPIO的原因
(参考:https://blog.csdn.net/u011976086/article/details/54342447)

勾上:


重新“Build”,没有错误了,也生成了 .hex 文件
用USB连接开发板和电脑,点击Load,报错:

这是因为没有仿真器的原因,但是我没有使用到仿真器(可以直接在Keil中点击Build就能在单片机上看到效果),所以不管它。
用mcuisp.exe串口程序下载工具来讲程序烧录到单片机

程序烧录进去了,但是LED灯不亮。(红灯是电源灯,D4蓝灯才是要点亮的灯)

原因是:代码写的不对,省略了两个步骤。
步骤一:开启时钟:因为STM32为了节约消耗,故上电时候外设时钟默认不开启。故我们需要开始GPIO的时钟。
步骤二:设置GPIO输出模式:stm32F103提供了4种输出模式和3种输出速度: 一般使用推挽模式
- 通用输出推挽
- 通用输出开漏
- 复用输出推挽:串口输出
- 复用输出开漏:IIC
打开STM32F103中文开发手册:找RCC时钟控制寄存器(GPIO挂在到APB2总线上),因为D4的LED是PC端口,所以这里找 IOPC端口


将位4置1,其他位不管,所以使用 |= 运算符,而它的真实地址是 = 起始地址 + 地址偏移
起始地址:0X40021000
地址偏移:0X18
所以,真实地址 = 0X40021018,将其强制转换成C中的指针并置1就是:
*(unsigned int *)0X40021018 |= ( 1<<4 );


设置输出模式:



两位一组,将其配置成0001,即0X01,即将1左移 8 位即可,因为2位一组,偏移地址为0X00,没有偏移,所以真实地址 = 起始地址 = 0X40011000
强制转换之后是:
*(unsigned int *)0X40011000 |= ( 1<<(4*2) );
经过三个步骤:
1.开启时钟
2.设置GPIO输出模式
3.输出低电平
代码如下:
#include "stm32f10x.h"
int main(void)
{
/* 配置RCC寄存器,使能GPIO口的时钟 */
*(unsigned int *)0X40021018 |= ( 1<<4 );
/* 配置CRL寄存器,配置为推挽输出 */
*(unsigned int *)0X40011000 |= ( 1<<(4*2) );
/* 配置ODR寄存器 */
*(unsigned int *)0X4001100C &= ~( 1<<2 );
while(1);
}
重新烧录到单片机中,发现D4的那个LED灯被点亮了!

简化代码:
#include "stm32f10x.h"
#define GPIO_RCC *(unsigned int *)0X40021018
#define GPIO_CRL *(unsigned int *)0X40011000
#define GPIO_ODR *(unsigned int *)0X4001100C
void soft_delay( unsigned int count )
{
for(; count!=0; count--);
}
int main(void)
{
/* 配置RCC寄存器,使能GPIO口的时钟 */
GPIO_RCC |= ( 1<<4 );
/* 配置CRL寄存器,配置为推挽输出 */
GPIO_CRL |= ( 1<<(4*2) );
/* 配置ODR寄存器 */
GPIO_ODR &= ~( 1<<2 );
while(1);
}

浙公网安备 33010602011771号