在Proteus软件仿真STM32F103寄存器玩俄罗斯方块之第一篇

这篇文章主要是代码分享,以及简单解析。
对代码哪里不理解的,欢迎找我讨论哈。
和上篇代码结构不一样的地方是多文件和分模块,使得工程更加有条理。
这篇文章主要是单片机引脚的输出操作,和PID的那篇文章高度重合,原因是这就是最基础的底层。

文件目录

  • 02_LCD12864 (这个是项目名)
    • button.c
      • button.h
      • GPIO.h
    • button_cfg.c
      • button_cfg.h
    • Game.c
      • Game.h
      • button.h
      • LCD12864.h
    • GPIO.c
      • Reg.h
      • GPIO.h
    • LCD12864.c
      • GPIO.h
      • LCD12864.h
      • LCD12864_cfg.h
    • main.c
      • Systick.h
      • RCC.h
      • LCD12864.h
      • button.h
      • Game.h
    • RCC.c
      • RCC.h
    • start.s
    • Systick.c
      • Reg.h
      • Systick.h

STM32F103最简短的启动文件

这部分代码在PID电机调速那篇文章已经分享过了,所以不做过多赘述。
只实现了中断向量表中的复位向量和SysTick向量。

    MODULE      ?cstartup
    
    SECTION     CSTACK:DATA:NOROOT(3)
    
    SECTION     .intvec:CODE:NOROOT(2)
    
    EXTERN      __iar_program_start
    EXTERN      SysTick_Handler
    PUBLIC      __vector_table
    
    DATA
    
__vector_table
    DCD         sfe(CSTACK)
    DCD         Reset_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         NMI_Handler
    DCD         SysTick_Handler
    
    THUMB
    
    PUBWEAK Reset_Handler
    SECTION .text:CODE:REORDER:NOROOT(2)
Reset_Handler
    LDR         R0,=__iar_program_start
    BX          R0
    
    PUBWEAK NMI_Handler
    SECTION .text:CODE:REORDER:NOROOT(1)
NMI_Handler
    B           NMI_Handler
    
    END

Reg.h文件内容

这部分代码在PID电机调速那篇文章已经分享过了,所以不做过多赘述。
只是单独形成了一个文件。
这部分都是寄存器结构体定义和寄存器指针宏定义。对于刚从51转到arm芯片的新手同学看着可能有点困难,这也是一个C语言知识点,typedef关键字的典型用法,但是你要理解并会用,51因为内存地址空间太小,所以很少这么用,arm芯片都是32位的地址空间,相对来说就可以称之为海量。

#ifndef __REG_H_
#define __REG_H_

#include "stdint.h"

typedef struct
{
    volatile uint32_t CTRL;
    volatile uint32_t LOAD;
    volatile uint32_t VAL;
    volatile uint32_t CALIB;
}SysTick_Def;

typedef struct
{
  volatile uint32_t CR;
  volatile uint32_t CFCR;
  volatile uint32_t CIR;
  volatile uint32_t APB2RSTR;
  volatile uint32_t APB1RSTR;
  volatile uint32_t AHBENR;
  volatile uint32_t APB2ENR;
  volatile uint32_t APB1ENR;
  volatile uint32_t BDCR;
  volatile uint32_t CSR;
}RCC_TypeDef;

typedef struct
{
   volatile uint32_t CRL;
   volatile uint32_t CRH;
   volatile uint32_t IDR;
   volatile uint32_t ODR;
   volatile uint32_t BSRR;
   volatile uint32_t BRR;
   volatile uint32_t LCKR;
}GPIO_TypeDef;

#define RCC_BASE        0x40021000
#define GPIOA_BASE      0x40010800
#define GPIOB_BASE      0x40010C00
#define GPIOC_BASE      0x40011000
#define GPIOD_BASE      0x40011400
#define GPIOE_BASE      0x40011800

#define SysTick_BASE    0xE000E010

#define RCC             ((RCC_TypeDef *)(RCC_BASE))
#define GPIOA           ((GPIO_TypeDef *)(GPIOA_BASE))
#define GPIOB           ((GPIO_TypeDef *)(GPIOB_BASE))
#define GPIOC           ((GPIO_TypeDef *)(GPIOC_BASE))
#define GPIOD           ((GPIO_TypeDef *)(GPIOD_BASE))
#define GPIOE           ((GPIO_TypeDef *)(GPIOE_BASE))

#define SysTick         ((SysTick_Def *)(SysTick_BASE))

#endif

SysTick配置以及初始化

这部分代码在PID电机调速那篇文章已经分享过了,所以不做过多赘述。
和PID那个工程有一点不一样哈,这里定时周期是1Khz,也就是1ms。
以下是h文件内容,文件名是Systick.h。

#ifndef __SYSTICK_H_
#define __SYSTICK_H_

#include "stdint.h"

void SysTick_Init(void);
uint32_t Get_SysTickCount(void);

#endif

以下是c文件内容,文件名是Systick.c。

#include "Reg.h"
#include "Systick.h"

void SysTick_Init(void)
{
    SysTick->LOAD = 8000-1;
    SysTick->VAL = 0;
    SysTick->CTRL = 0x07;
}

static volatile uint32_t TickCount = 0;

void SysTick_Handler(void)
{
    TickCount ++;
    if(TickCount >= 10001)
    {
        TickCount = 1;
    }
}

uint32_t Get_SysTickCount(void)
{
    return TickCount;
}

RCC初始化及相关文件内容

这个文件没有什么特殊的,就是简单的打开了所有外设的时钟。
依旧还是h文件。

#ifndef __RCC_H_
#define __RCC_H_

#include "Reg.h"

void RCC_Init(void);

#endif

这个是C文件。

#include "RCC.h"

void RCC_Init(void)
{
    RCC->APB2ENR = 0xFFFFFFFF;
}

GPIOB引脚的初始化代码文件

这部分代码在PID电机调速那篇文章已经分享过了,所以不做过多赘述。
以下是h文件内容。

#ifndef __GPIO_H_
#define __GPIO_H_

#include "stdint.h"

void PB_Out_Init(uint8_t pin);
void PB_Out(uint8_t pin,uint8_t State);
void PB_In_Init(uint8_t pin);
uint8_t  PB_In(uint8_t pin);

#endif

下边的内容是C文件。
这个里边能学到的也就是位操作。
位置1,位清0,左移,右移操作。
寄存器的读改写操作。

#include "Reg.h"
#include "GPIO.h"

void PBH_Out_Init(uint8_t pin)
{
    uint32_t reg = GPIOB->CRH;
    reg &= ~(0xF << ((pin & 0x07) << 2));
    reg |= (0x02 << ((pin & 0x07) << 2));//推挽输出 20M
    GPIOB->CRH = reg;
}

void PBL_Out_Init(uint8_t pin)
{
    uint32_t reg = GPIOB->CRL;
    reg &= ~(0xF << ((pin & 0x07) << 2));
    reg |= (0x02 << ((pin & 0x07) << 2));
    GPIOB->CRL = reg;
}

void PB_Out_Init(uint8_t pin)
{
    if(pin & 0x08)
        PBH_Out_Init(pin);
    else
        PBL_Out_Init(pin);
}

void PB_Out(uint8_t pin,uint8_t State)
{
    if(State)
        GPIOB->BSRR = 0x01 << (pin & 0x0F);
    else
        GPIOB->BRR = 0x01 << (pin & 0x0F);
}

void PBH_In_Init(uint8_t pin)
{
    uint32_t reg = GPIOB->CRH;
    reg &= ~(0xF << ((pin & 0x07) << 2));
    reg |= (0x08 << ((pin & 0x07) << 2));//上下拉输入
    GPIOB->CRH = reg;
}

void PBL_In_Init(uint8_t pin)
{
    uint32_t reg = GPIOB->CRL;
    reg &= ~(0xF << ((pin & 0x07) << 2));
    reg |= (0x08 << ((pin & 0x07) << 2));
    GPIOB->CRL = reg;
}

void PB_In_Init(uint8_t pin)
{
    if(pin & 0x08)
        PBH_In_Init(pin);
    else
        PBL_In_Init(pin);
}

uint8_t PB_In(uint8_t pin)
{
    return (GPIOB->IDR >> pin) & 0x01;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值