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

ops/2025/1/12 17:50:21/

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

目录

  • 文件目录
  • STM32F103最简短的启动文件
  • Reg.h文件内容
  • SysTick配置以及初始化
  • RCC初始化及相关文件内容
  • GPIOB引脚的初始化代码文件

文件目录

  • 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      ?cstartupSECTION     CSTACK:DATA:NOROOT(3)SECTION     .intvec:CODE:NOROOT(2)EXTERN      __iar_program_startEXTERN      SysTick_HandlerPUBLIC      __vector_tableDATA__vector_tableDCD         sfe(CSTACK)DCD         Reset_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         NMI_HandlerDCD         SysTick_HandlerTHUMBPUBWEAK Reset_HandlerSECTION .text:CODE:REORDER:NOROOT(2)
Reset_HandlerLDR         R0,=__iar_program_startBX          R0PUBWEAK NMI_HandlerSECTION .text:CODE:REORDER:NOROOT(1)
NMI_HandlerB           NMI_HandlerEND

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));//推挽输出 20MGPIOB->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);elsePBL_Out_Init(pin);
}void PB_Out(uint8_t pin,uint8_t State)
{if(State)GPIOB->BSRR = 0x01 << (pin & 0x0F);elseGPIOB->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);elsePBL_In_Init(pin);
}uint8_t PB_In(uint8_t pin)
{return (GPIOB->IDR >> pin) & 0x01;
}

http://www.ppmy.cn/ops/149105.html

相关文章

用c实现C++类(八股)

在 C 语言中&#xff0c;虽然没有内建的面向对象编程&#xff08;OOP&#xff09;特性&#xff08;如封装、继承、多态&#xff09;&#xff0c;但通过一些编程技巧&#xff0c;我们仍然可以模拟实现这些概念。下面将用通俗易懂的方式&#xff0c;逐步介绍如何在 C 中实现封装、…

C#中前台线程与后台线程的区别及设置方法

线程分为前台线程和后台线程&#xff0c;它们在行为上有着根本的区别&#xff0c;这些区别直接影响到程序的运行方式和退出机制。以下是对这两种线程模式的详细解释&#xff0c;以及如何在C#中设置它们&#xff1a; 一、前台线程与后台线程的定义 前台线程&#xff1a;前台线…

人工智能学习路线全链路解析

一、基础准备阶段&#xff08;预计 2-3 个月&#xff09; &#xff08;一&#xff09;数学知识巩固与深化 线性代数&#xff08;约 1 个月&#xff09;&#xff1a; 矩阵基础&#xff1a;回顾矩阵的定义、表示方法、矩阵的基本运算&#xff08;加法、减法、乘法&#xff09;&…

Redis:持久化机制

Redis 的持久化机制是确保数据在服务器重启后不会丢失的关键功能。它提供了两种主要的持久化方式:RDB(Redis Database Backup)快照和 AOF(Append Only File)日志记录。 1. RDB 快照(Redis Database Backup) 简介 概念:RDB 是 Redis 在指定的时间点将内存中的所有数据…

kubernetes第七天

1.影响pod调度的因素 nodeName 节点名 resources 资源限制 hostNetwork 宿主机网络 污点 污点容忍 Pod亲和性 Pod反亲和性 节点亲和性 2.污点 通常是作用于worker节点上&#xff0c;其可以影响pod的调度 语法&#xff1a;key[value]:effect effect:[ɪˈfek…

Spring Boot中的扫描注解如何使用

在 Spring Boot 中&#xff0c;扫描注解是指通过注解来告诉 Spring 框架应该扫描哪些包、哪些类或哪些特定的组件&#xff0c;并将其作为 Spring 容器中的 bean 进行管理。Spring Boot 主要通过以下几种注解来实现自动扫描&#xff1a; ComponentScanSpringBootApplicationCom…

如何使用Spring Boot框架整合Redis:超详细案例教程

目录 # 为什么选择Spring Boot与Redis整合&#xff1f; 1. 更新 pom.xml 2. 配置application.yml 3. 创建 Redis 配置类 4. Redis 操作类 5. 创建控制器 6. 启动应用程序 7. 测试 # 为什么选择Spring Boot与Redis整合&#xff1f; 将Spring Boot与Redis整合可以充分利…

【面试题】技术场景 7、定位系统瓶颈

系统瓶颈定位方法总述 面试官询问如何快速定位系统瓶颈&#xff0c;旨在考察线上调试经验。主要方法包括&#xff1a; 压测&#xff1a;在项目上线前找出系统瓶颈并修复。监控工具或链路追踪工具&#xff1a;项目上线后用于实时监控或评测找瓶颈。Arthas&#xff08;原阿尔萨…