一、创建工程
1.首先安装好keil,以及对应芯片的数据包后(这里选用的是stm32 F1系列)。
此时电脑里还没有一个工程文件,首先我们找到
打开Keil uVision5,找到File,然后点击New uVision Project
2.选择要使用的芯片。
这里因为我们提前下载了数据包,直接找就可以
3.对Run-Time Environment进行设置
设置完成后,点击OK,这样一个工程就建立完成
二、编写程序及编译
在新建的工程下面,右键单击Source Group 1,选择Add New Item to Group,添加一个文件main.c,然后添加以下代码
//宏定义,用于存放stm32寄存器映射
#define PERIPH_BASE ((unsigned int)0x40000000)//AHB
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
//GPIOA_BASE=0x40000000+0x10000+0x0800=0x40010800,该地址为GPIOA的基地址
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
//GPIOB_BASE=0x40000000+0x10000+0x0C00=0x40010C00,该地址为GPIOB的基地址
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
//GPIOC_BASE=0x40000000+0x10000+0x1000=0x40011000,该地址为GPIOC的基地址
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
//GPIOD_BASE=0x40000000+0x10000+0x1400=0x40011400,该地址为GPIOD的基地址
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
//GPIOE_BASE=0x40000000+0x10000+0x0800=0x40011800,该地址为GPIOE的基地址
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
//GPIOF_BASE=0x40000000+0x10000+0x0800=0x40011C00,该地址为GPIOF的基地址
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
//GPIOG_BASE=0x40000000+0x10000+0x0800=0x40012000,该地址为GPIOG的基地址
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define LED0 MEM_ADDR(BITBAND(GPIOA_ODR_Addr,8))
//#define LED0 *((volatile unsigned long *)(0x422101a0)) //PA8
//定义typedef类型别名
typedef struct
{
volatile unsigned int CR;
volatile unsigned int CFGR;
volatile unsigned int CIR;
volatile unsigned int APB2RSTR;
volatile unsigned int APB1RSTR;
volatile unsigned int AHBENR;
volatile unsigned int APB2ENR;
volatile unsigned int APB1ENR;
volatile unsigned int BDCR;
volatile unsigned int CSR;
} RCC_TypeDef;
#define RCC ((RCC_TypeDef *)0x40021000)
//定义typedef类型别名
typedef struct
{
volatile unsigned int CRL;
volatile unsigned int CRH;
volatile unsigned int IDR;
volatile unsigned int ODR;
volatile unsigned int BSRR;
volatile unsigned int BRR;
volatile unsigned int LCKR;
} GPIO_TypeDef;
//GPIOA指向地址GPIOA_BASE,GPIOA_BASE地址存放的数据类型为GPIO_TypeDef
#define GPIOA ((GPIO_TypeDef *)GPIOA_BASE)
void LEDInit( void )
{
RCC->APB2ENR|=1<<2; //GPIOA 时钟开启
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;
}
//粗略延时
void Delay_ms( volatile unsigned int t)
{
unsigned int i,n;
for (n=0;n<t;n++)
for (i=0;i<800;i++);
}
int main(void)
{
LEDInit();
while (1)
{
LED0=0;//LED熄灭
Delay_ms(500);//延时时间
LED0=1;//LED亮
Delay_ms(500);//延时时间
}
}
编译结果如图
三、程序的仿真调试
1.首先进行调试的设置
2.开始调试
点击debug,开始调试
3.分析生成的hex文件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i020O909-1665138213671)(C:\Users\yes\AppData\Roaming\Typora\typora-user-images\image-20221007175205377.png)]
1、“:”表示一行的开始;
2、第1、2个字符0和2,即“0x02”表示本行包含的数据长度为2个字节,四个字符。
3、第3、4、5、6个字符,固定这4位表示地址,即“0000”表示数据存储的起始地址,表示在0x0000地址开始存放本行包含的16个数据。
4、第7、8个字符,固定这2位表示本行包含数据数据的类型,即“00”表示本行包含的数据为实际烧写的数据。而数据的类型有如下几种:
“00”表示实际数据记录
“01”表示文件结束记录
“02”表示扩展段地址记录
“04”表示扩展线性地址记录
5、由前两个字符“02”可知本行的数据长度位2个字节,所有往后的4个字符就是本行包含的数据,每两个字符表示一个字节数据,总共有2个字节数据。跟最前两个字符决定的长度一致。但是这个数据的长度不是固定的
6、最后两个字符为本行的校验码。
通过上面的几点分析可以总结出hex文件的每一行的格式:
<0x3a>[数据长度1Byte][数据地址2Byte][数据类型1Byte][数据nByte]
[验证码1Byte]<0x0d><0x0a>
四、总结
在安装以及破解mdk的时候,要注意mdk的版本,最新版本的mdk不能使用注册机。使用的时候会出现无法打开芯片列表的问题,下载的数据包也导入不了mdk。
五、参考资料