这篇文章主要是代码分享,以及简单解析。
对代码哪里不理解的,欢迎找我讨论哈。
和上篇代码结构不一样的地方是多文件和分模块,使得工程更加有条理。
这篇文章主要是单片机引脚的输出操作,和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
- button.c
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;
}