EDN首页   博客首页

58

关于投票
RVMDK纯软件仿真

通常大家都说keil的纯软件仿真功能无比的强大,它到底强大到哪种程度呢?简单地来说,它能够仿真到几乎所有的内部资源及外围的IO口。

 

 

如上图所示,几乎所有的IO口、串口、I2CSPIAD等,都能够仿真。呵呵,够强大了吧?下面以外围IO口的流水灯仿真及AD转换为例,来慢慢说明。

大家可以下载下面这个软件包进行结合我的例子同步:

 

rar

 

点击看大图

 

下载完后直接可以编译,编译后,没有错误和警告,然后就可以点击上图中的那个红色的d字形按钮进行 debug,然后点击“peripherals”按钮,选择GPIO,再在子菜单中选择Port0(因为在程序中我是将流水灯写在对应的Port0管脚上的)。再按一下全速运行,呵呵,是不是发现IO0SET的第十六位到第二十三位的钩依次打上呢?这是因为它们依次就高电平,如果我们在实际的开发板上接上LED(阳极接限流电阻再接IO口,阴极接地)的话,这样就会使我们的LED闪啊闪的,像流水一样~~~~~~~~

AD转换呢?我们有AD转换,首先要模拟出一个模拟电压才行。点击Debug后,不要点全速运行,在Debug菜单中选择function editor (open Ini file),会提示我们打开一个脚本文件,把下面这样文件加进去:

rar

脚本文件的内容是:

//

// Generate Sine Wave Signal on AD Channel 0

//

signal void AIN0(void)  {

  float volts;        // peak-to-peak voltage

  float frequency;    // output frequency in Hz

  float offset;       // voltage offset

  float duration;     // duration in Seconds

  float val;

  long  i, end; 

 

  volts     = 1.5;

  offset    = 1.6;

  frequency = 1800;

  duration  = 0.1;

 

  printf ("Sine Wave Signal on AD Channel 0.\n");

 

  end = (duration * 100000);

  while(1)  {

    val = __sin (frequency * (((float) STATES) / CLOCK) * 2 * 3.1415926);

    AIN0 = (val * volts) + offset;

    swatch (0.00001);                // in 10 uSec steps

  }

}

进行保存,编译,下面按下全速运行,再打开逻辑分析窗口,这个时候你看到正弦波了吗?肯定看不到啦!

这是为什么呢?因为我们还没有把它加到模拟IO口呢!那么怎么添加呢?在下面这个窗口中:

 

 

 

点击看大图

 

 

我们再看看前面这样脚本的内容,那个函数是将一个正弦波信号加到一个叫AIN0的管脚,这可以在command 窗口中输入 dir vtreg”命令来查看这个模拟的CPU有哪些模拟资源。那么,我们将这个函数添加到模拟端口,输入这个脚本函数的名称:“AIN0()”,这个时候看到正弦波了吗?看到了!看到一个正弦波在跳啊跳的,多开心啊!

总体如下图:

 

点击看大图

 

 

呵呵,不用硬件资源,直接可以进行STM32的学习,是不是觉得十分爽啊?

 

如果觉得此文章对你有帮助的话,麻烦帮我点一下文章左上角的“顶一下”,谢谢!

 

 

 

 

 

 

 

系统分类: 单片机
用户分类: STM32
标签: STM32 MDK 软件 仿真
来源: 原创
发表评论 阅读全文(2402) | 回复(7)

42

关于投票
RVMDK环境下STM32的链接过程

想不想知道在RVMDK环境下面是怎么将STM32的各个用户代码链接成一个HEX文件的呢?下面一一讲解。

我们随便打开一个工程文件,例如:下面一个工程文件,

rar

进行编译一下,出现以下信息:

Build target 'EK-STM32F'

assembling STM32F10x.s...

compiling STM32_Init.c...

compiling Retarget.c...

compiling Usart.c...

compiling LCD.c...

linking...

Program Size: Code="2288" RO-data=268 RW-data=288 ZI-data=1040 

FromELF: creating hex file...

".\Obj\Usart.axf" - 0 Error(s), 0 Warning(s).

 

这里我们可以看到,编译一开始,RVMDK环境开始对每一个 *.s 文件和 *.c文件进行编译,然后到了“linking”的时候,就是编译器开始对各个文件进行链接。把所有的 *.o文件链接成一个可执行的文件,生成一个 *.hex文件,这个文件就是我们可以下载到flash中执行的文件。

我们再看main()函数下面(在usart.c下面)调用了很多的函数,比如:printf()lcdWrStr()等等,这个函数根本就不在usart.c函数里面,而是在其它的 *.c函数里面,那在编译的时候编译器根本就不认识这样一些函数,那怎么办呢?于是就只把它当成一个标号预留下来,接着往下编译,直到把所有的*.s 文件和 *.c文件都编译完,那么,在我们所有的目标文件里面会预留相当多的标号,这些标号都会有一些相对的地址,在编译完所有的文件后,即在linking的前面,编译器会将这些所有的标号变成绝对地址,即分配一个物理地址,这样,就实现了对整个工程的链接。

那么,我们怎么知道每段代码的具体位置呢?这个就需要借助一个 *.sct链接脚本的帮助了。在 options 菜单下面我们可以选择系统自带的链接脚本或者自己添加链接脚本。

点击看大图

 

如上图,如果我们将那个 use Memory Layout from Target Dialog 打钩的话,那么我们就是选择系统自动生成的脚本,如果不打钩的话,那么就是手动添加。我们把钩去掉,按下Scatter File右边的Edit,就可以看到Usart.sct文件的内容了。如下:

; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************

 

LR_IROM1 0x08000000 0x00020000  {    ; load region size_region

  ER_IROM1 0x08000000 0x00020000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$$Sections)

   .ANY (+RO)

  }

  RW_IRAM1 0x20000000 0x00005000  {  ; RW data

   .ANY (+RW +ZI)

  }

}

 

我们知道,在启动代码的过程中,对一些全局变量及堆栈的拷贝过程是由一些宏来完成的,这个宏的名字就是 InRoot$$Sections 是由它来完成这样一个定位。

我们来举个例子,如下图所示,

 

点击看大图

 

 

我们将片内ROM空间分成两半,分完后如下:

 

点击看大图

 

单击确定。再进行编译,可以看到,Usart.sct文件已经改变了。变成为:

; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************

 

LR_IROM1 0x08000000 0x00010000  {    ; load region size_region

  ER_IROM1 0x08000000 0x00010000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$$Sections)

   .ANY (+RO)

  }

  RW_IRAM1 0x20000000 0x00005000  {  ; RW data

   .ANY (+RW +ZI)

  }

}

我们可以看到,片内flash已经分为两部分,但是另外一个没有任何文件。我们也可以在另外一部分里面装进数据,如:在 Project workspace里面右击Initialisation,选择“options for Group Initialisation Code/const”选项改为:IROM2 [0x8010000-0x801FFFF],点击确定,再次编译,将会发现,IROM2里面有数据啦~~~

; *************************************************************

; *** Scatter-Loading Description File generated by uVision ***

; *************************************************************

 

LR_IROM1 0x08000000 0x00010000  {    ; load region size_region

  ER_IROM1 0x08000000 0x00010000  {  ; load address = execution address

   *.o (RESET, +First)

   *(InRoot$$Sections)

   .ANY (+RO)

  }

  RW_IRAM1 0x20000000 0x00005000  {  ; RW data

   .ANY (+RW +ZI)

  }

}

 

LR_IROM2 0x08010000 0x00010000  {

  ER_IROM2 0x08010000 0x00010000  {  ; load address = execution address

    STM32_Init.o (+RO)

  }

}

 

呵呵,如果觉得对你有帮助的话,麻烦帮我点击左上方的“顶一下”,谢谢!

 

 

 

 

系统分类: 单片机
用户分类: STM32
标签: STM32 链接
来源: 原创
发表评论 阅读全文(2130) | 回复(3)
总共 , 当前 /