STM32F103的流水灯点亮版本1(寄存器地址操作)

一、了解STM32最小系统核心板(STM32F103C8T6,国际上又统称 STM32 Blue Bill开发板)的电路原理图,用Proteus 设计一个STM32最小系统板+LED流水灯实验原理图,仿真运行。

1.keil5准备源代码

(1)点击project,选择new μvision project,创建工程名为lsd,点击保存,点击保存然后弹出的芯片选择,我们选择芯片STM32F103RB,然后点击ok。
在这里插入图片描述
我们再进行选择,对相应选项进行勾选,之后点击“OK"
在这在这里插入图片描述
里插入图片描述

(2)工程创建完毕,开始创建源文件,点击file,选择new,写入代码,代码如下:

#include "stm32f10x.h"

GPIO_InitTypeDef GPIO_InitStructure;
void delay_ms(uint32_t ms)
{
	uint32_t i_cnt,j_cnt;
	for(i_cnt=0;i_cnt<3000;i_cnt++);
	for(j_cnt=0;j_cnt<ms;j_cnt++);
}
uint32_t i;
int main(void)
{   
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
	GPIOC->BSRR=0xff;
	while (1)
	{
	  for(i=0;i<8;i++)
	  {
		delay_ms(99000);
		GPIOC->BRR=(1<<i);   
		delay_ms(99000);
		GPIOC->BSRR=(1<<i);
	  }
	  for(i=0;i<8;i++)
	  {
		  delay_ms(99000);
		  GPIOC->BRR=0x000000ff;
		  delay_ms(99000);
		  GPIOC->BSRR=0x000000ff;  
	  }
	}
}

点击保存,这里的名称后缀必须是是.c。右键点击左侧project窗口的source Group1,选择相应的选项把.c文件添加到工程里。

(3)右键中选择Option for Target,然后勾选Create HEX file,编译生成hex文件。
在这里插入图片描述

2.Proteus仿真

(1)点击创建新工程,输入工程名、安装路径,选择从选中的模板中创建原理图(DEFAULT),选择不创建PCB布版设计,选择创建固件项目,其中:系列选择Cortex-M3,Controller选择STM32F103R6,点击下一步。
在这里插入图片描述
点击完成,即可创建成功。

(2)添加实验所需元件灯,点击左上角“P”字图标,输入LED-GREEN,并点击确认选中;添加实验所需电阻,点击左边P,然后进入下图,在关键字中输入RES,并点击确认选中。

将灯和电阻分别添加到原理图,然后右键电阻,编辑电阻,设置其阻值为50(默认阻值过大,不更换led电流达不到,亮不起来)。原理图如下:
在这里插入图片描述
(3)双击stm32f103r6芯片,进入Program File 选择LED生成的hex文件,并配置Crystal Frequency改成8M(设置晶振为8M)
在这里插入图片描述
效果图:在这里插入图片描述

二. 、以 STM32最小系统核心版(STM32F103C8T6)+面板板+3只(或更多)红绿蓝LED 搭建电路,使用GPIOA、GPIOB、GPIOC这3个端口控制LED灯,轮流闪烁,间隔时长1秒。

1.GPIOx端口的各寄存器地址和详细参数

(1)首先需要知道的是,STM32中对于GPIO口的操作,无非就是操作下面的寄存器而已,所谓的标准库也好,HAL库也好,它们都只是对操作寄存器的过程进行了封装,目的是为了减轻编程时的工作负担:

两个32位的配置寄存器:GPIOx_CRL、GPIOx_CRH
两个32位数据寄存器:GPIOx_IDR、GPIOx_ODR
一个32位的置位/复位寄存器:GPIOx_BSRR
一个16位复位寄存器:GPIOx_BRR
一个32位锁定寄存器:GPIOx_LCKR

时钟地址
在stm32手册中我们可以查到寄存器组起始地址,得到时钟地址如图下:
在这里插入图片描述
GPIO地址
在这里插入图片描述
可以知道时钟RCC属于AHB总线,然后GPIO端口A B C属于APB2总线。

GPIO的配置寄存器CRL和CRH

配置对应引脚寄存器,基地址+偏移量。
每个 GPI/O 端口有两个 32 位配置寄存器(GPIOx_CRL,GPIOx_CRH),两个 32位数据寄存器(GPIOx_IDR,GPIOx_ODR),一个 32 位置位/复位寄存器(GPIOx_BSRR),一个 16 位复位寄存器(GPIOx_BRR)和一个 32 位锁定寄存器(GPIOx_LCKR)。
这里我们用的就是CRL和CRH,这两个寄存器的全称是:端口配置低寄存器(GPIOx_CRL) (x=A…E) 和 端口配置高寄存器(GPIOx_CRH) (x=A…E)。
根据数据手册中列出的每个 I/O 端口的特定硬件特征, GPIO 端口的每个位可以
由软件分别配置成多种模式。
− 输入浮空
− 输入上拉
− 输入下拉
− 模拟输入
− 开漏输出
− 推挽式输出
− 推挽式复用功能
− 开漏复用功能
每个 I/O 端口位可以自由编程,然而 I/0 端口寄存器必须按 32 位字被访问(不允许
半字或字节访问)。GPIOx_BSRR 和 GPIOx_BRR 寄存器允许对任何 GPIO 寄存
器的读/更改的独立访问;这样,在读和更改访问之间产生 IRQ 时不会发生危险。

//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL		*((unsigned volatile int*)0x40010C00)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)

CRL
在这里插入图片描述
CRH
在这里插入图片描述
设置输出模式为推挽输出,输出速度为2Mhz

GPIOA_CRL&=0xFFF0FFFF;		//设置位 清零	
	GPIOA_CRL|=0x00020000;		//PA4推挽输出,把第19、18、17、16位变为0010
	GPIOB_CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOB_CRL|=0x00200000;		//PB5推挽输出,把第23、22、21、20变为0010
	GPIOC_CRH&=0xFF0FFFFF;		//设置位 清零	
	GPIOC_CRH|=0x00200000;		//PC14推挽输出,把第23、22、21、20变为0010

2.用C语言寄存器方式编程实现

(1)新建文件
打开keil5,在project下选择New uVision Project,输入文件名LEDLIGHT,然后选择与我们相符合的STM32F103C8
在这里插入图片描述
然后在左侧目录下点开Target 1,右键Source Group 1,选择Add New ITem to Group。
(2)代码写入

//--------------APB2使能时钟寄存器------------------------
#define RCC_AP2BENR	*((unsigned volatile int*)0x40021018)
	//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRL	*((unsigned volatile int*)0x40010800)
#define	GPIOA_ODR	*((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 ------------------------
#define GPIOB_CRH	*((unsigned volatile int*)0x40010C04)
#define	GPIOB_ODR	*((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH	*((unsigned volatile int*)0x40011004)
#define	GPIOC_ODR	*((unsigned volatile int*)0x4001100C)
//-------------------简单的延时函数-----------------------
void SystemInit(void);
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<<5;		//PA5低电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x1<<14;		//PC14高电平
}
void B_LED_LIGHT(){
	GPIOA_ODR=0x1<<5;		//PA5高电平
	GPIOB_ODR=0x0<<9;		//PB9低电平
	GPIOC_ODR=0x1<<14;		//PC14高电平
}
void C_LED_LIGHT(){
	GPIOA_ODR=0x1<<5;		//PA5高电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x0<<14;		//PC14低电平	
}
//------------------------主函数--------------------------
int main()
{
	int j=100;
	RCC_APB2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
	RCC_APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
	RCC_APB2ENR|=1<<4;			//APB2-GPIOC外设时钟使能
	//这两行代码可以合为 RCC_APB2ENR|=1<<3|1<<4;
	GPIOA_CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOA_CRL|=0X00200000;		//PA5推挽输出
	GPIOA_ODR|=1<<5;			//设置PA5初始灯为灭
	
	GPIOB_CRH&=0xFFFFFF0F;		//设置位 清零	
	GPIOB_CRH|=0x00000020;		//PB9推挽输出
	GPIOB_ODR|=0x1<<9;			//设置初始灯为灭
	
	GPIOC_CRH&=0xF0FFFFFF;		//设置位 清零
	GPIOC_CRH|=0x02000000;   	//PC14推挽输出
	GPIOC_ODR|=0x1<<14;			//设置初始灯为灭	
	while(j)
	{	
		A_LED_LIGHT();	
		Delay_ms(1000000);
		B_LED_LIGHT();
		Delay_ms(1000000);
		C_LED_LIGHT();
		Delay_ms(1000000);
	}
}
void SystemInit(){
	
}

(3)编译调试
点击左上角的build图标,然后看到无报错警告,且已自动生成hex文件
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 要使用STM32F103寄存器方式点亮LED流水灯,需要按照以下步骤进行: 1. 首先,需要配置GPIO引脚为输出模式。可以通过设置GPIOx_CRL或GPIOx_CRH寄存器来实现。例如,如果要使用PA引脚,可以将GPIOA_CRL寄存器的第位和第1位设置为01,表示将PA引脚配置为输出模式。 2. 接下来,需要使用GPIOx_BSRR寄存器来设置或清除引脚的电平。例如,如果要点亮PA引脚上的LED,可以将GPIOA_BSRR寄存器的第位设置为1,表示将PA引脚的电平设置为高电平。 3. 然后,可以使用延时函数来控制LED的亮灭时间。例如,可以使用SysTick定时器来实现延时功能。 4. 最后,可以使用循环语句和位运算符来实现LED流水灯效果。例如,可以使用for循环和左移运算符来实现LED从左到右依次亮起的效果。 需要注意的是,使用寄存器方式编程需要对STM32F103寄存器结构和寄存器位的含义有一定的了解。同时,需要注意寄存器的读写顺序和操作的正确性,以避免出现意外的错误。 ### 回答2: STM32F103是一款高性能、低功耗、易于开发的微控制器,它能为嵌入式设备提供强大的计算和控制能力。在使用STM32F103进行开发时,头文件和寄存器操作是必不可少的一部分。 很多初学者都想通过点亮LED来入门STM32F103的开发,这里以寄存器方式点亮LED流水灯为例进行讲解: 首先需要初始化GPIO口,确定要控制的IO口和使用的引脚。这里用到了重映射技术,将LED1连接至PD2引脚(具体可以参考datasheet),可以将GPIO口D对应的寄存器地址复制到某个变量用于后续的操作。 代码示例: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO, ENABLE);//使能GPIO时钟 GPIO_InitTypeDef GPIO_InitStructure;//定义GPIO初始化结构体 GPIO_InitStructure.GPIO_Pin= GPIO_Pin_2;//选择PD2引脚 GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed= GPIO_Speed_10MHz;//输出速度10MHz GPIO_Init(GPIOD, &GPIO_InitStructure);//将设置好的GPIO配置应用 接下来,可以编写流水灯的代码,通过设置GPIO口输出高低电平,控制LED灯的亮灭。循环体中,分别点亮/熄灭LED,并加上适当的时间延时,从而实现流水灯的效果。 代码示例: while(1) { GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_SET);//将PD2输出高电平,点亮LED1 delay(50);//延时 GPIO_WriteBit(GPIOD, GPIO_Pin_2, Bit_RESET);//将PD2输出低电平,熄灭LED1 delay(50);//延时 } 代码执行上述代码后,即可实现STM32F103寄存器方式点亮LED流水灯的效果。需要注意的是,该示例代码中的延时函数需要自行编写,建议使用STM32CubeMX来生成延时函数。此外,还需要注意GPIO口的配置以及时钟使能,以免出现硬件问题。 以上就是关于STM32F103寄存器方式点亮LED流水灯的简单介绍与实现步骤。希望本文对初学者入门STM32F103开发有所帮助。 ### 回答3: 首先,启用STM32F103寄存器进行点亮LED流水灯需要进行以下准备步骤: 1. 确认所需引脚LED的连接方式。此处假设我们将LED连接到引脚PB12,那么需要将PB12设置为输出模式。 2. 配置系统时钟,以便使用定时器来控制LED的闪烁速度。不同的系统时钟配置方式可能会略有不同,但主要是设置时钟源和最终频率。 3. 配置定时器,以便以适当的频率闪烁LED。这通常涉及到设置定时器的时钟源、预分频和计数器值。 4. 配置NVIC(Nested Vectored Interrupt Controller)中断,以便在定时器计数完成时处理中断。这需要设置中断源和优先级,以便定时器中断可以正确地触发。 了解了以上准备工作之后,下面开始实现点亮LED流水灯寄存器方式程序: 1. 在头文件中加入相关寄存器定义,方便后续程序的操作。 2. 在主函数中进行引脚配置: ``` RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; //使能PB引脚时钟 GPIOB->CRH &= ~(0xF << 16); //清零位16~19 GPIOB->CRH |= (0x3 << 16); //设置位16~17为01,即输出模式 ``` 3. 配置定时器,以便生成适当的延迟时间: ``` RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; //使能TIM3时钟 TIM3->PSC = 7200 - 1; //预分频器7200,即频率为8KHz TIM3->ARR = 1000 - 1; //计数器自动重载值999,即1s的闪烁周期 TIM3->CR1 |= TIM_CR1_ARPE; //开启自动重载 TIM3->CR1 &= ~(TIM_CR1_DIR); //向上计数 TIM3->CR1 &= ~(TIM_CR1_CMS); //开启边缘对齐模式 TIM3->DIER |= TIM_DIER_UIE; //开启更新事件中断 TIM3->CR1 |= TIM_CR1_CEN; //启动计数器 ``` 4. 配置NVIC中断,以便在定时器计数完成时更新LED的状态: ``` NVIC_EnableIRQ(TIM3_IRQn); //使能TIM3中断 NVIC_SetPriority(TIM3_IRQn, 0); //设置TIM3中断优先级为最高 ``` 5. 在计时器中断处理中更新LED的状态,以实现流水灯效果: ``` void TIM3_IRQHandler(void){ if(TIM3->SR & TIM_SR_UIF){ //判断是否为更新中断 TIM3->SR &= ~(TIM_SR_UIF); //清除更新中断标志 static int count=0; static int flag=1; if(count==0){ GPIOB->ODR |= GPIO_ODR_ODR12; //点亮PB12,LED1亮 flag=1; } else if(count==1){ GPIOB->ODR &= ~(GPIO_ODR_ODR12); //熄灭PB12,LED1灭 GPIOB->ODR |= GPIO_ODR_ODR13; //点亮PB13,LED2亮 } else if(count==2){ GPIOB->ODR &= ~(GPIO_ODR_ODR13); //熄灭PB13,LED2灭 GPIOB->ODR |= GPIO_ODR_ODR14; //点亮PB14,LED3亮 } else if(count==3){ GPIOB->ODR &= ~(GPIO_ODR_ODR14); //熄灭PB14,LED3灭 GPIOB->ODR |= GPIO_ODR_ODR15; //点亮PB15,LED4亮 } else if(count==4){ GPIOB->ODR &= ~(GPIO_ODR_ODR15); //熄灭PB15,LED4灭 GPIOB->ODR |= GPIO_ODR_ODR14; //点亮PB14,LED3亮 } else if(count==5){ GPIOB->ODR &= ~(GPIO_ODR_ODR14); //熄灭PB14,LED3灭 GPIOB->ODR |= GPIO_ODR_ODR13; //点亮PB13,LED2亮 } else if(count==6){ GPIOB->ODR &= ~(GPIO_ODR_ODR13); //熄灭PB13,LED2灭 GPIOB->ODR |= GPIO_ODR_ODR12; //点亮PB12,LED1亮 flag=0; } if(flag){ count++; } else{ count--; } } } ``` 上述代码中,首先判断是否为计数器更新中断,然后根据计数值的不同更新LED的状态,实现流水灯效果。其中,计数值的变化可以通过flag来判断是递增还是递减,以实现LED灯的正向或反向流动。 总体来说,通过以上代码实现了基于STM32F103寄存器点亮LED流水灯,可以调整定时器的时钟源和计数器值来实现不同的闪烁效果。虽然这种方式比较繁琐,但对于有一定经验的开发者来说,可以更精准地控制硬件,实现更高效的程序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值