打印
[其他ST产品]

Proteus内部编程仿真STM32

[复制链接]
456|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
l63t89|  楼主 | 2022-12-31 19:54 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
想在没有开发板的基础上形象逼真仿真基于STM32的设计,除了Proteus无出之右了吧,但目前没有很好地指导直接在Proteus中C编程来仿真STM32设计的帖子供参考,绝大部分的帖子还是借助于Keil MDK或者STM32CubeMX之类的工具,编译成HEX文件之后导入Proteus仿真,程序需要修改时,就得来回切换,反复修改程序、编译程序、导入HEX文件,调试起来非常不方便,也没有充分利用Proteus的优势,费时费力,降低调试效率。

使用特权

评论回复
评论
l63t89 2022-12-31 19:56 回复TA
———————————————— 版权声明:本文为CSDN博主「宝玉飞」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/tj_nonstoper/article/details/124078197 
沙发
l63t89|  楼主 | 2022-12-31 19:55 | 只看该作者
STM32开发简介

STM32开发可以分别基于HAL库、库函数或寄存器编程来进行,而基于Proteus链接的Keil for ARM编译器生成的代码(如图1),相比HAL和库函数不具有优势,但HAL(硬件抽象层)和库函数也无非是寄存器软件化,使软件编程更方便,可读性更强,但基于寄存器编程也有代码简略,可以清晰了解编程意图的优点,下面我们以寄存器编程为主导举一个例子来介绍一下在Proteus内部C语言编程仿真STM32设计的实际应用。

使用特权

评论回复
板凳
l63t89|  楼主 | 2022-12-31 19:57 | 只看该作者
STM32实例简述

选用STM32F103T6芯片,利用PA8/PB2的推挽输出以1秒为周期交替点亮熄灭白色LED灯,系统时钟采用PLL锁相环9倍频8MHz的HSE外部晶振源来获得,电路原理如下图2,Keil for ARM编译器的设置,可以参考Keil for C51的指导设置。

使用特权

评论回复
地板
l63t89|  楼主 | 2022-12-31 19:57 | 只看该作者

使用特权

评论回复
5
l63t89|  楼主 | 2022-12-31 19:58 | 只看该作者
Proteus内部寄存器C语言编程

1、时钟函数Clock_Init()

熟悉一个芯片先从时钟开始,这话一点都不假,我们的设置也是先从时钟入手,分别使能内外时钟并等待就绪,APB1二分频,APB2和AHB不分频,PLL对外部时钟HSE先9倍频再赋给系统时钟,代码如图3:

使用特权

评论回复
6
l63t89|  楼主 | 2022-12-31 19:59 | 只看该作者

使用特权

评论回复
7
l63t89|  楼主 | 2022-12-31 20:00 | 只看该作者
GPIO函数 LED_Init()

先使能GPIO时钟,初始化PA8/PB2之后,设置为推挽逻辑高初始输出。代码如图4:

使用特权

评论回复
8
l63t89|  楼主 | 2022-12-31 20:02 | 只看该作者

使用特权

评论回复
9
l63t89|  楼主 | 2022-12-31 20:03 | 只看该作者
延时函数 delay_nms()

外部晶振源是8MHz,9倍频后就是72MHz,延时0.5秒的话,需要delay_nms(250)。代码如图5:

使用特权

评论回复
10
l63t89|  楼主 | 2022-12-31 20:04 | 只看该作者

使用特权

评论回复
11
l63t89|  楼主 | 2022-12-31 20:05 | 只看该作者
主函数main()

调用Clock时钟和GPIO初始化函数,然后以1秒为周期循环点亮和熄灭LED灯。代码如图6:

使用特权

评论回复
12
l63t89|  楼主 | 2022-12-31 20:07 | 只看该作者

使用特权

评论回复
13
l63t89|  楼主 | 2022-12-31 20:08 | 只看该作者
宏定义

紧跟头文件定义了GPIO操作的宏定义,位带操作可以像C51对GPIO进行位操作。代码如图7:

使用特权

评论回复
14
l63t89|  楼主 | 2022-12-31 20:09 | 只看该作者

使用特权

评论回复
15
l63t89|  楼主 | 2022-12-31 20:09 | 只看该作者
仿真结果图示

图8的仿真结果借助了GIF图,实际亮灭切换没这么快。

使用特权

评论回复
16
l63t89|  楼主 | 2022-12-31 20:10 | 只看该作者

使用特权

评论回复
17
l63t89|  楼主 | 2022-12-31 20:11 | 只看该作者
完整代码

几乎每行代码都给出了注释,方便快速理解。
/* Main.c file generated by liyufei
*
* Created:   周六 4月 9 2022
* Processor: STM32F103T6
* Compiler:  Keil for ARM
*/

#include <stm32f103x6.h>
#include <stm32f1xx.h>

//IO口操作宏定义,位带操作,实现51类似的GPIO控制功能
#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 PBout(2) // PB2

//时钟设置
//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;  // 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<<8;        //PA8 初始输出高
   GPIOB->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输出0
      LED1 = 1; //PB2输出1
      delay_nms(250); //延时0.5S
      LED0 = 1; //PA8输出1
      LED1 = 0; //PB2输出0
      delay_nms(250); //延时0.5S
   }
}   

使用特权

评论回复
18
l63t89|  楼主 | 2022-12-31 20:11 | 只看该作者
总结

上面例子的仿真成功,至少说明利用Proteus内部C语言编程进行STM32的设计仿真是行得通的,STM32的仿真有别路可选。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

798

帖子

1

粉丝