目录
一、基于寄存器点亮LED灯
1、寄存器的定义
寄存器的功能是存储二进制代码,它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码,故存放n位二进制代码的寄存器,需用n个触发器来构成。
2、创建一个基于寄存器的keil工程
1)、新建一个文件夹,命名为stm32基于寄存器点亮led,打开keil,点击Project,选择New uVision Project,选择文件夹(stm32基于寄存器点亮led),新建项目(寄存器LED),选择开发板STM32F103C8。
2)、在线添加库文件
用寄存器控制 STM32 时,不需要在线添加库文件,可以直接关掉。
3)、添加文件
①添加已经存在文件
在新建的工程中添加启动文件(startup_stm32f10x_hd.s),该文件可以先到固件库中复制到此处startup_stm32f10x_hd.s。
②创建新文件
stm32f10x.h
手动新建,用于存放寄存器映射的代码,暂时为空。
main.c
手动新建,用于存放 main 函数,暂时为空。
4)、配置魔术棒选项卡
①Target设置,目的是能够使用printf
②Output设置,以便在编译时生成hex文件
③Listing设置,让输出文件定位到Listing文件夹
④Debug设置
⑤Utilities设置
3、基于寄存器的LED流水灯
1)、编写代码
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
void Delay_ms(volatile unsigned int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ODR=0x0<<4; //PA4低电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x0<<9; //PB9低电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x0<<13; //PC13低电平
}
int main(){
int j=100;
// 开启时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= ~(1111<<(4*5)); //设置位 清零
GPIOC_CRH|=(1<<(4*5)); //PC13推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位 清零
GPIOA_CRL|=0x00010000; //PA4推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<13);
GPIOA_ODR |= (1<<4);
while(j){
B_LED_LIGHT();
Delay_ms(10000);
C_LED_LIGHT();
Delay_ms(10000);
A_LED_LIGHT();
Delay_ms(10000);
}
}
2)、实验结果
二、基于固件库点亮LED灯
1、固件库的定义
固件库又称固件函数库,是⼀个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每⼀个外设的驱动描述和应⽤实例,为开发者访问底层硬件提供了⼀个中间API,通过使⽤固件函数库,⽆需深⼊掌握底层硬件细节,开发者就可以轻松应⽤每⼀个外设。因此,使⽤固态函数库可以⼤⼤减少⽤户的程序编写时间,进⽽降低开发成本。每个外设驱动都由⼀组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由⼀个通⽤API (application programming interface 应⽤编程界⾯)驱动,API对该驱动程序的结构,函数和参数名称都进⾏了标准化
2、创建一个基于寄固件库的keil工程
方法类似于寄存器的创建。
不同点:
需要添加libraries文件
3、基于固件库的LED流水灯
1)编写代码
``
#include "stm32f10x.h" // Device header
#include "Delay.h"
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;//创建结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//设置为推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;//初始化GPIOA的全部引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//将串口设置为高电平,因为接线方式导致LED灯默认为低电平点亮,故先熄灭LED灯
GPIO_SetBits(GPIOA,GPIO_Pin_0);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_SetBits(GPIOA,GPIO_Pin_3);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
GPIO_SetBits(GPIOA,GPIO_Pin_7);
while (1)
{
GPIO_ResetBits(GPIOA,GPIO_Pin_0);//低电平点亮
Delay_ms(1000); //延时1s
GPIO_SetBits(GPIOA,GPIO_Pin_0); //高电平熄灭
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_2);
GPIO_ResetBits(GPIOA,GPIO_Pin_3);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_3);
GPIO_ResetBits(GPIOA,GPIO_Pin_4);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_4);
GPIO_ResetBits(GPIOA,GPIO_Pin_5);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_5);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_6);
GPIO_ResetBits(GPIOA,GPIO_Pin_7);
Delay_ms(1000);
GPIO_SetBits(GPIOA,GPIO_Pin_7);;
}
}
2)实验结果
三、两种方式的对比
寄存器方法
缺点:
①开发速度慢
②程序可读性差
③维护复杂
优点:
①具体参数更直观
②程序运行占用资源少
开库开发方式则正好弥补了寄存器开发的缺点。
通过两个方式的实现,你会发现采用寄存器开发的方式,需要不断地查看对应的手册,了解对应寄存器的地址。