一. Proteus仿真运行STM32最小系统板+LED流水灯
1. 使用keil软件编写LED流水灯代码生成可运行.hex文件\n最小系统板原理图:
代码如下:
#define PERIPH_BASE ((unsigned int)0x40000000)//AHB
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800,该地址为GPIOA的基地址
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
//GPIOB_BASE=0x40000000+0x10000+0x0C00=0x40010C00,该地址为GPIOB的基地址
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
//GPIOC_BASE=0x40000000+0x10000+0x1000=0x40011000,该地址为GPIOC的基地址
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
//GPIOD_BASE=0x40000000+0x10000+0x1400=0x40011400,该地址为GPIOD的基地址
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
//GPIOE_BASE=0x40000000+0x10000+0x0800=0x40011800,该地址为GPIOE的基地址
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
//GPIOF_BASE=0x40000000+0x10000+0x0800=0x40011C00,该地址为GPIOF的基地址
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
//GPIOG_BASE=0x40000000+0x10000+0x0800=0x40012000,该地址为GPIOG的基地址
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define LED0 MEM_ADDR(BITBAND(GPIOA_ODR_Addr,4)) //LED1为PA4引脚
#define LED1 MEM_ADDR(BITBAND(GPIOB_ODR_Addr,9)) //LED2为PB9引脚
#define LED2 MEM_ADDR(BITBAND(GPIOC_ODR_Addr,13)) //LED3为PC13引脚
volatile unsigned long * LED_[3]={0};//定义一个四个LED引脚地址的数组
//定义typedef类型别名
typedef struct
{
volatile unsigned int CR;
volatile unsigned int CFGR;
volatile unsigned int CIR;
volatile unsigned int APB2RSTR;
volatile unsigned int APB1RSTR;
volatile unsigned int AHBENR;
volatile unsigned int APB2ENR;
volatile unsigned int APB1ENR;
volatile unsigned int BDCR;
volatile unsigned int CSR;
} RCC_TypeDef;
#define RCC ((RCC_TypeDef *)0x40021000)
//定义typedef类型别名
typedef struct
{
volatile unsigned int CRL;
volatile unsigned int CRH;
volatile unsigned int IDR;
volatile unsigned int ODR;
volatile unsigned int BSRR;
volatile unsigned int BRR;
volatile unsigned int LCKR;
} GPIO_TypeDef;
//GPIOA指向地址GPIOA_BASE,GPIOA_BASE地址存放的数据类型为GPIO_TypeDef
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
void LEDInit( void )
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00030000;//PA4 推挽输出
GPIOA->ODR|=1<<4; //PA4 输出高
RCC->APB2ENR|=1<<3; //使能PORTB时钟
GPIOB->CRH&=0XFFFFFF0F;
GPIOB->CRH|=0X00000030;//PB9 推挽输出
GPIOB->ODR|=1<<9; //PB9 输出高
RCC->APB2ENR|=1<<4; //使能PORTC时钟
GPIOC->CRH&=0XFF0FFFFF;
GPIOC->CRH|=0X00300000;//PC13 推挽输出
GPIOC->ODR|=1<<13; //PC13 输出高
}
//粗略延时
void Delay_ms( volatile unsigned int t)
{
unsigned int i,n;
for (n=0;n<t;n++)
for (i=0;i<800;i++);
}
int main(void)
{
LEDInit();
unsigned int flag=0;//定义一个点亮的LED标志
LED_[0]=&LED0;
LED_[1]=&LED1;
LED_[2]=&LED2;//给地址数组进行赋值
while (1)
{
if(flag>2)
{
flag=0;
}
*LED_[flag]=0;//LED亮
Delay_ms(5000);//延时
*LED_[flag]=1;//LED灭
flag++;
}
}
2.生成.hex文件:
3.Proteus构建原理图并运行仿真:
二. 红绿蓝LED 搭建电路,使用GPIOA、GPIOB、GPIOC这3个端口控制LED灯,轮流闪烁,间隔时长1秒
1. 程序设计思路及GPIOx端口各寄存器地址和详细参数
程序设计思路:
完成基本配置,再编写LED流水灯代码:
配置时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB
程序设计中最为重要的是GPIO端口的配置,GPIO端口配置完成之后,我们就能控制LED点亮点灭了,但是如果我们需要实现精确延时1s后LED灯闪烁,我们就需要添加延时函数,这部分系统中断,在这里我调用的是正点原子写好的延时函数。各GPIO端口的寄存器地址:
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800,该地址为GPIOA的基地址#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
//GPIOB_BASE=0x40000000+0x10000+0x0C00=0x40010C00,该地址为GPIOB的基地址#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
//GPIOC_BASE=0x40000000+0x10000+0x1000=0x40011000,该地址为GPIOC的基地址#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
//GPIOD_BASE=0x40000000+0x10000+0x1400=0x40011400,该地址为GPIOD的基地址#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
//GPIOE_BASE=0x40000000+0x10000+0x0800=0x40011800,该地址为GPIOE的基地址#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
//GPIOF_BASE=0x40000000+0x10000+0x0800=0x40011C00,该地址为GPIOF的基地址#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
//GPIOG_BASE=0x40000000+0x10000+0x0800=0x40012000,该地址为GPIOG的基地址
2.c语言寄存器方式编程实现:
代码:
#define PERIPH_BASE ((unsigned int)0x40000000)//AHB
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800,该地址为GPIOA的基地址
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
//GPIOB_BASE=0x40000000+0x10000+0x0C00=0x40010C00,该地址为GPIOB的基地址
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
//GPIOC_BASE=0x40000000+0x10000+0x1000=0x40011000,该地址为GPIOC的基地址
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
//GPIOD_BASE=0x40000000+0x10000+0x1400=0x40011400,该地址为GPIOD的基地址
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
//GPIOE_BASE=0x40000000+0x10000+0x0800=0x40011800,该地址为GPIOE的基地址
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
//GPIOF_BASE=0x40000000+0x10000+0x0800=0x40011C00,该地址为GPIOF的基地址
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
//GPIOG_BASE=0x40000000+0x10000+0x0800=0x40012000,该地址为GPIOG的基地址
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define LED0 MEM_ADDR(BITBAND(GPIOA_ODR_Addr,4)) //LED1为PA4引脚
#define LED1 MEM_ADDR(BITBAND(GPIOB_ODR_Addr,9)) //LED2为PB9引脚
#define LED2 MEM_ADDR(BITBAND(GPIOC_ODR_Addr,13)) //LED3为PC13引脚
volatile unsigned long * LED_[3]={0};//定义一个四个LED引脚地址的数组
//定义typedef类型别名
typedef struct
{
volatile unsigned int CR;
volatile unsigned int CFGR;
volatile unsigned int CIR;
volatile unsigned int APB2RSTR;
volatile unsigned int APB1RSTR;
volatile unsigned int AHBENR;
volatile unsigned int APB2ENR;
volatile unsigned int APB1ENR;
volatile unsigned int BDCR;
volatile unsigned int CSR;
} RCC_TypeDef;
#define RCC ((RCC_TypeDef *)0x40021000)
//定义typedef类型别名
typedef struct
{
volatile unsigned int CRL;
volatile unsigned int CRH;
volatile unsigned int IDR;
volatile unsigned int ODR;
volatile unsigned int BSRR;
volatile unsigned int BRR;
volatile unsigned int LCKR;
} GPIO_TypeDef;
//GPIOA指向地址GPIOA_BASE,GPIOA_BASE地址存放的数据类型为GPIO_TypeDef
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
#define GPIOC ((GPIO_TypeDef *)GPIOC_BASE)
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE)
void LEDInit( void )
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00030000;//PA4 推挽输出
GPIOA->ODR|=1<<4; //PA4 输出高
RCC->APB2ENR|=1<<3; //使能PORTB时钟
GPIOB->CRH&=0XFFFFFF0F;
GPIOB->CRH|=0X00000030;//PB9 推挽输出
GPIOB->ODR|=1<<9; //PB9 输出高
RCC->APB2ENR|=1<<4; //使能PORTC时钟
GPIOC->CRH&=0XFF0FFFFF;
GPIOC->CRH|=0X00300000;//PC13 推挽输出
GPIOC->ODR|=1<<13; //PC13 输出高
}
//粗略延时
void Delay_ms( volatile unsigned int t)
{
unsigned int i,n;
for (n=0;n<t;n++)
for (i=0;i<800;i++);
}
int main(void)
{
LEDInit();
unsigned int flag=0;//定义一个点亮的LED标志
LED_[0]=&LED0;
LED_[1]=&LED1;
LED_[2]=&LED2;//给地址数组进行赋值
while (1)
{
if(flag>2)
{
flag=0;
}
*LED_[flag]=0;//LED亮
Delay_ms(5000);//延时
*LED_[flag]=1;//LED灭
flag++;
}
}
3. 烧录代码并使得系统板成功工作运行LED点亮实验
选择输出的.hex文件
烧录\n![在这里插入图片描述](https://img-blog.csdnimg.cn/2800bf46f0fb486888c584401224a300.jpeg
运行成果:
总结:
作为一名新人小白,我在此时此刻已经感受到这个领域的复杂性和挑战性,已经给自己留下压力。在学习过程中,我更加扎实地掌握了有关嵌入式方面的知识,也通过解决一些实际问题发现了我在学习过程中的知识欠缺与经验不足,践行过而能改,善莫大焉的知行观。实践对于本课程是十分重要的,只有尝试和改正才能助我们修成一门学问。以后无论学习过程有多苦,我都将变苦为乐,在实践中学习更多知识,面对即将到来的挑战。