也许很多人都会讨厌keil 或者stm32 cube繁杂的配置过程,选出型号之后还有诸多的配置,那么有没有一种办法用上keil arm的编译器来编译我们的stm32,又不使用其他不熟悉的编译器(如yagarto)《用proteus直接仿真stm32-可以完全丢弃编程器》呢?
其实我们知道,我们使用stm32一般会有两套库文件,一套是HAL,一套是标准库。
keil arm中使用的就是标准库。那么我们怎么来使用它呢?
1、在proteus中配置好keil arm
在配置前,我们要确保我们的keil arm已经在我们的机器上安装好了(keil arm 安装好就可以的,无所谓破不破解,因为我们只要用到它的编译器)。然后打开proteus,在compiler config中配置如下:
不会配置的,就直接点下面的check按钮则自动完成。
2、新建工程绘制电路
新建一个工程,并在器件库中找到stm32的芯片,如我们这里选择stm32f103r6,则电路绘制可以如下:
3、配置电路和芯片
新建的芯片电源连接会有两个没有连接,VssA与VDDA,可以按照下面的连接来设置
电源电压,我们也设置到3.3V
最后,我们要给芯片配置一下频率为8MHZ,如下图:
4、代码
/* Main.c file generated by New Project wizard
*
* Created: 周六 8月 13 2022
* Processor: STM32F103R6
* Compiler: Keil for ARM
*/
#include <stm32f103x6.h>
#include <stm32f1xx.h>
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //PA输出
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //PB输出
#define LED0 PAout(8) // PA8
#define LED1 PAout(4) // PA4
int flag=0;
//时钟设置
//RCC_CR_HSION,RCC_CR_HSEON,RCC_CR_HSERDY,RCC_CFGR_PLLSRC等在头文件stm32f103x6.h有定义
void Clock_Init(unsigned char PLL)
{
unsigned char temp_value = 0;
RCC->CR|=RCC_CR_HSION; //使能内部高速时钟HSION
while(!(RCC_CR_HSIRDY>>1)); //等待PLL锁定
RCC->CR|=RCC_CR_HSEON; //外部高速时钟使能HSEON
while(!(RCC_CR_HSERDY>>17)); //等待外部时钟就绪
RCC->CFGR=0x00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
RCC->CFGR|=(PLL-2)<<18; //设置 PLL值 2~16,本例为9倍频
RCC->CFGR|=RCC_CFGR_PLLSRC; //PLLSRC选择外部时钟HSE为PLL输入源
RCC->CR|=RCC_CR_PLLON; //使能PLL
while(!(RCC_CR_PLLRDY>>25)); //等待 PLL锁定
RCC->CFGR|=RCC_CFGR_SW_PLL; //PLL作为系统时钟
while(temp_value!=RCC_CFGR_SWS_PLL) //等待PLL作为系统时钟设置成功
{
temp_value=RCC->CFGR;
temp_value&=0x0C;
}
}
//毫秒延时
void delay_nms(unsigned int time)
{
unsigned int i=0;
while(time--)
{
i=12000;
while(i--) ;
}
}
//为LED亮灭进行GPIO口初始化
void LED_Init(void)
{
RCC->APB2ENR|= RCC_APB2ENR_IOPAEN; //使能 PORTA时钟
GPIOA->CRH&=0XFFF0FFF0; //初始化PA8
GPIOA->CRH|=3<<0; //PA8 推挽输出
GPIOA->CRL&=0XFFF0FFFF; //初始化PA4
GPIOA->CRL|=3<<16; //PA4 推挽输出
GPIOA->ODR|=1<<4; //PA4 初始输出高
GPIOA->ODR|=1<<4; //PA8 初始输出高
}
//main函数
int main (void)
{
Clock_Init(9); //设PLL为系统时钟,频率为HSE外部时钟8MHz的9倍
LED_Init(); //GPIO初始化
while (1)
{
if(flag==1)
break;
LED0 = 0; //PA8输出0
LED1 = 1; //PA4输出1
delay_nms(100); //延时0.5S
LED0 = 1; //PA8输出1
LED1 = 0; //PA4输出0
delay_nms(100); //延时0.5S
}
return 0;
}
5、运行效果
总结:
这里我们使用的是标准库,而且没有通过stm32 cube的设备配置,直接通过了寄存器来设置端口,对于初学者不好理解,或者说从字面上不好理解,但如果真是准备扎实学习stm32的童鞋,那更能帮助咱们理解寄存器的使用。
相比函数库去设定端口的代码更能够理解底层的机理些。
不明白的可以去查看一下stm32的手册,收获一定更大!
百度网盘链接提取码 密码:lwcg