使用STM32配置寄存器实现流水灯

目录

一、STM32F103C8T6基本介绍

(一)系统构架

(二)STM32最小系统板的电路原理图

二、STM32F103C8T6寄存器配置流水灯

(一)GPIO端口的初始化设置

1、打开时钟:

2、初始化GPIO口

3、设置高电平

(二)实际应用


一、STM32F103C8T6基本介绍

(一)系统构架

1.在小容量、中容量和 大容量产品中,主系统由以下部分构成:

(1) 四个驱动单元:

  • Cortex™-M3内核DCode总线(D-bus),和系统总线(S-bus)
  • 通用DMA1和通用DMA2
  • (2)四个被动单元:

  • 内部SRAM
  • 内部闪存存储器
  •  FSMC
  • AHB到APB的桥(AHB2APBx),它连接所有的APB设备
  • 这些都是通过一个多级的AHB总线构架相互连接的,如下图所示:

    2.在互联型产品中,主系统由以下部分构成:

    (1)五个驱动单元:

  • Cortex™-M3内核DCode总线(D-bus),和系统总线(S-bus)
  • 通用DMA1和通用DMA2
  • 以太网DMA
  • (2) 三个被动单元

  • 内部SRAM
  • 内部闪存存储器
  • AHB到APB的桥(AHB2APBx),它连接所有的APB设备
  • 这些都是通过一个多级的AHB总线构架相互连接的,如图所示:

    3.结构中的总线

    (1)ICode总线:该总线将 Cortex™-M3 内核的指令总线与 Flash 指令接口相连接。指令预取在此总线上完成。

    (2)DCode总线:该总线将 Cortex™-M3 内核的 DCode 总线与闪存存储器的数据接口相连接(常量加载和调试访问)。

    (3)系统总线:此总线连接 Cortex™-M3 内核的系统总线(外设总线)到总线矩阵,总线矩阵协调着内核和 DMA 间的访问。

    (4)DMA总线:此总线将 DMA 的 AHB 主控接口与总线矩阵相联,总线矩阵协调着CPU的DCode和DMA到SRAM、闪存和外设的访问。

    (5)总线矩阵:此总线矩阵协调内核系统总线和 DMA 主控总线之间的访问仲裁。此仲裁利用轮 换算法。此总线矩阵由三个驱动部件(CPU 的 DCode、系统总线和 DMA 总线)和 三个被动部件(闪存存储器接口、SRAM 和 AHB2APB 桥)构成。 AHB 外设通过总线矩阵与系统总线相连,允许DMA 访问。

    (6)AHB/APB桥(APB):两个 AHB/APB 桥在 AHB 和 2 个 APB 总线间提供同步连接。APB1 操作速度限 于 36MHz,APB2 操作于全速(最高 72MHz)。

    (二)STM32最小系统板的电路原理图

    二、STM32F103C8T6寄存器配置流水灯

    (一)GPIO端口的初始化设置

          GPIO是STM32芯片上的通用输入输出端口,通过这些引脚,STM32可以与外部设备连接,实现通讯、控制和数据采集等功能。STM32芯片的GPIO被分成多个组,每组包含16个引脚,如STM32F103VET6型号芯片有GPIOA至GPIOE共5组GPIO,总计100个引脚,这些引脚都具有基本的输入输出功能。

          点亮LED灯,实现流水灯效果需要用到GPIO端口。为了点亮LED灯,进行以下三个步骤:

    1. 打开GPIO口的时钟
    2. 初始化GPIO口(选择推挽输出)
    3. 设置低电平

    1、打开时钟:

    (1)GPIO的地址:

    根据芯片手册查询端口相关资料得到端口地址如下图所示:

    (2)时钟的地址:

    由上图可得:

  • RCC的起始地址为:0x40021000
  • APB2外设时钟使能寄存器的偏移地址是0x18
  • 因此可以得到实际地址为:0x40021000 + 0x18 = 0x40021018
  • 则打开三个IO口的时钟需要将三个位都置1:

    #define RCC_APB2ENR (*(unsigned int *)0x40021018)
     
    // 打开时钟
    RCC_APB2ENR |= (1<<3);  // 打开 GPIOB 时钟
    RCC_APB2ENR |= (1<<4);  // 打开 GPIOC 时钟
    RCC_APB2ENR |= (1<<2);  // 打开 GPIOA 时钟
     

    2、初始化GPIO口

    通过学习可以得到GPIO口有如下八种模式:

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟输入
  • 开漏输出
  • 推挽式输出
  • 推挽式复用功能
  • 开漏复用功能
  • 本次实验使用推挽输出:

    端口1-7为低,端口8-15为高。每个引脚由四个位控制。
     PB0、PC15、PA0的设置具体代码如下:

    #define GPIOB_CRH (*(unsigned int *)0x40010C04)
    #define GPIOC_CRH (*(unsigned int *)0x40011004)
    #define GPIOA_CRL (*(unsigned int *)0x40010800)
    // 设置 GPIO 为推挽输出,即00,同时频率为10MHz,即01
    // 设置 GPIOB 最后四位为 0001 (B0)
    GPIOB_CRL |= (1<<0); // 最后一位设置为1
    GPIOB_CRL &= ~(0xE); // 倒数二、三、四位设置为0
    // 设置 GPIOC 前四位为 0001 (C15)
    GPIOC_CRH |= (1<<28); // 第四位设置为1
    GPIOC_CRH &= ~(0xE0000000); // 前三位设置为0
    // 设置 GPIOA 最后四位为 0001 (A0)
    GPIOA_CRL |= (1<<0); // 最后一位设置为1
    GPIOA_CRL &= ~(0xE); // 倒数二、三、四位设置为0
    

    3、设置高电平

    注:输出高电平则为1,低电平则为0

    以GPIOB和0号引脚(B0)为例,将其设置为低电平:

    #define GPIOA_ODR (*(unsigned int *)0x4001080C)
    GPIOB_ODR &= ~(1<<0);  // 最后一位变0

    将相应的bit位设置为高电位则灯不亮,GPIO的A0、B0、C15代码如下:

    //给GPIOA、GPIOB、GPIOC配置输入寄存器
    #define GPIOB_ODR (*(unsigned int *)0x40010C0C)
    #define GPIOC_ODR (*(unsigned int *)0x4001100C)
    #define GPIOA_ODR (*(unsigned int *)0x4001080C)
    // 3个LED初始化为不亮(即高点位)
    GPIOB_ODR |= (1<<0); // 最后一位设置为1
    GPIOC_ODR |= (1<<15); // 倒数第15位设置为1
    GPIOA_ODR |= (1<<0); // 最后一位设置为1
    

    (二)实际应用

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

    Proteus原理图:

    代码编写:

     
    #define GPIOB_BASE 0x40010C00
    #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 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<<4;		//PA4低电平
    	GPIOB_ODR=0x1<<9;		//PB9高电平
    	GPIOC_ODR=0x1<<15;		//PC15高电平
    }
    void B_LED_LIGHT(){
    	GPIOA_ODR=0x1<<4;		//PA4高电平
    	GPIOB_ODR=0x0<<9;		//PB9低电平
    	GPIOC_ODR=0x1<<15;		//PC15高电平
    }
    void C_LED_LIGHT(){
    	GPIOA_ODR=0x1<<4;		//PA4高电平
    	GPIOB_ODR=0x1<<9;		//PB9高电平
    	GPIOC_ODR=0x0<<15;		//PC15低电平	
    }
     
    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 &= 0x0fffffff; //设置位 清零		
    	GPIOC_CRH|=0x30000000;  //PC15推挽输出
     
     
    	GPIOA_CRL &= 0xfff0ffff; //设置位 清零		
    	GPIOA_CRL|=0x00010000; //PA4推挽输出
     
    	// 3个LED初始化为不亮(即高点位)
    	GPIOB_ODR |= (1<<9); 
    	GPIOC_ODR |= (1<<15); 
    	GPIOA_ODR |= (1<<4);  
    	
    	while(j){
    
    		A_LED_LIGHT();
    		Delay_ms(1000000);
    		
    		B_LED_LIGHT();
    		Delay_ms(1000000);
     
    		C_LED_LIGHT();
    		Delay_ms(1000000);
     
    
    	}
    	
    }
     
     
    void SystemInit(){
    	
    }

    2、题目:STM32最小系统核心板子出厂时已经焊接好了1个led灯(标注了PC13处),一般可通过此灯的点亮让编程者验证自己烧录的代码是否正常运行了。请查阅最小版电路原理图和相关资料,将这个灯也用在流水灯中,重编新程序。

    代码编写:

     
    #define GPIOB_BASE 0x40010C00
    #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 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<<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 &= 0xff0fffff; //设置位 清零		
    	GPIOC_CRH|=0x00300000;  //PC15推挽输出
     
     
    	GPIOA_CRL &= 0xfff0ffff; //设置位 清零		
    	GPIOA_CRL|=0x00010000; //PA4推挽输出
     
    	// 3个LED初始化为不亮(即高点位)
    	GPIOB_ODR |= (1<<9); 
    	GPIOC_ODR |= (1<<13); 
    	GPIOA_ODR |= (1<<4);  
    	
    	while(j){
    
    		A_LED_LIGHT();
    		Delay_ms(3000);
    		
    		B_LED_LIGHT();
    		Delay_ms(2000);
     
    		C_LED_LIGHT();
    		Delay_ms(3000);
     
    
    	}
    	
    }
     
     
    void SystemInit(){
    	
    }

    开发板效果:

    流水灯

    参考博客:STM32F103的流水灯点亮版本1(寄存器地址操作)_pc13推挽输出-CSDN博客

    作者:一瓶勇闯天涯的雪花

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32配置寄存器实现流水灯

    发表回复