目录
一、背景
二、STM32开发简介
三、STM32实例简述
四、Proteus内部寄存器编程
1、时钟函数Clock_Init()
2、GPIO函数 LED_Init()
3、延时函数 delay_nms()
4、主函数main()
5、宏定义
五、仿真结果图示
六、完整代码
七、总结
一、背景
想在没有开发板的基础上形象逼真仿真基于STM32的设计,除了Proteus无出之右了吧,但目前没有很好地指导直接在Proteus中C编程来仿真STM32设计的帖子供参考,绝大部分的帖子还是借助于Keil MDK或者STM32CubeMX之类的工具,编译成HEX文件之后导入Proteus仿真,程序需要修改时,就得来回切换,反复修改程序、编译程序、导入HEX文件,调试起来非常不方便,也没有充分利用Proteus的优势,费时费力,降低调试效率。
二、STM32开发简介
STM32开发可以分别基于HAL库、库函数或寄存器编程来进行,而基于Proteus链接的Keil for ARM编译器生成的代码(如图1),相比HAL和库函数不具有优势,但HAL(硬件抽象层)和库函数也无非是寄存器软件化,使软件编程更方便,可读性更强,但基于寄存器编程也有代码简略,可以清晰了解编程意图的优点,下面我们以寄存器编程为主导举一个例子来介绍一下在Proteus内部C语言编程仿真STM32设计的实际应用。
图1 ProteusKeil for ARM编译器生成的代码
三、STM32实例简述
选用STM32F103T6芯片,利用PA8/PB2的推挽输出以1秒为周期交替点亮熄灭白色LED灯,系统时钟采用PLL锁相环9倍频8MHz的HSE外部晶振源来获得,电路原理如下图2,Keil for ARM编译器的设置,可以参考Keil for C51的指导设置,详情请参看下面我之前的帖子,链接如下:
Proteus和Keil C51联调仿真完整解析(附程序)_宝玉飞的博客-CSDN博客
图2STM32F103T6电路原理图
四、Proteus内部寄存器C语言编程
1、时钟函数Clock_Init()
熟悉一个芯片先从时钟开始,这话一点都不假,我们的设置也是先从时钟入手,分别使能内外时钟并等待就绪,APB1二分频,APB2和AHB不分频,PLL对外部时钟HSE先9倍频再赋给系统时钟,代码如图3:
图3时钟设置
2、GPIO函数 LED_Init()
先使能GPIO时钟,初始化PA8/PB2之后,设置为推挽逻辑高初始输出。代码如图4:
图4 GPIO设置
3、延时函数 delay_nms()
外部晶振源是8MHz,9倍频后就是72MHz,延时0.5秒的话,需要delay_nms(250)。代码如图5:
图5 延时函数
4、主函数main()
调用Clock时钟和GPIO初始化函数,然后以1秒为周期循环点亮和熄灭LED灯。代码如图6:
图6 主函数
5、宏定义
紧跟头文件定义了GPIO操作的宏定义,位带操作可以像C51对GPIO进行位操作。代码如图7:
图7 GPIO宏定义
五、仿真结果图示
图8的仿真结果借助了GIF图,实际亮灭切换没这么快。
图8 仿真结果
六、完整代码
几乎每行代码都给出了注释,方便快速理解。
/* Main.c file generated by liyufei * * Created: 周六 4月 9 2022 * Processor: STM32F103T6 * Compiler:Keil for ARM */#include #include //IO口操作宏定义,位带操作,实现51类似的GPIO控制功能#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<CR|=RCC_CR_HSION;//使能内部高速时钟HSIONwhile(!(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)<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;// 250x12000 = 36000000,每隔0.5秒LED灯反转while(i--) ; }}//为LED亮灭进行GPIO口初始化void LED_Init(void) { RCC->APB2ENR|= RCC_APB2ENR_IOPAEN; //使能 PORTA时钟 RCC->APB2ENR|= RCC_APB2ENR_IOPBEN; //使能 PORTB时钟 GPIOA->CRH&=0XFFFFFFF0;//初始化PA8 GPIOA->CRH|=0X00000003;//PA8 推挽输出 GPIOA->ODR|=1<CRL&=0XFFFFF0FF;//初始化PB2 GPIOB->CRL|=0X00000300;//PB2 推挽输出 GPIOB->ODR|=1<<2;//PB2 初始输出高 }//main函数int main (void) { Clock_Init(9); //设PLL为系统时钟,频率为HSE外部时钟8MHz的9倍LED_Init(); //GPIO初始化while (1) {LED0 = 0; //PA8输出0LED1 = 1; //PB2输出1delay_nms(250); //延时0.5SLED0 = 1; //PA8输出1LED1 = 0; //PB2输出0delay_nms(250); //延时0.5S }}
七、总结
上面例子的仿真成功,至少说明利用Proteus内部C语言编程进行STM32的设计仿真是行得通的,STM32的仿真有别路可选。