文章目录
前言
-
开发环境
Proteus 8.15 Keil 5 MDK 正点原子STM32开发板
一、C51程序的设计和仿真:流水灯仿真
1、程序编译
#include <reg51.h>
#include <intrins.h>
//延迟函数
void delay_ms(int a)
{
int i,j;
for(i=0;i<a;i++)
{
for(j=0;j<1000;j++) _nop_();
}
}
void main(void)
{
while(1){
P0=0xfe;
while(1){
delay_ms(50);
P0=P0<<1;
P0=P0+1;
delay_ms(50);
}
}
}
2、仿真结果
二、寄存器方式点亮LED
1、安装MDK软件和stm32包
参考链接:ARM开发:使用MDK编译stm32简单程序(闪烁LED)
Keil C51和MDK是针对不同类型MCU的两款集成开发工具,Keil C51是针对51内核的单片机,如AT89C51、STC89C51等,MDK-ARM是针对ARM内核单片机,如STM32F1、LPC1788等
2、新建工程
-
(1)打开Keil新建一个工程
-
(2)选择STM32芯片
-
(3)勾选相应选项并点击OK完成创建
-
(4)创建LED.c文件并保存,将其添加到Source Group1中
3、调试配置
- (1)首先点击魔法棒,然后在弹出的窗口内,点击 Debug,勾选 Use Simulator ,再选择 ULINK2/ME Cortex Debugger ,并点击 Settings 。
- (2)更改Port为JTAG,Reset可以设置为Autodetect或SYSRESEETREQ
4、程序编写
(1)配置寄存器
led.h
#ifndef __LED_H
#define __LED_H
void LED_Init(void);
#endif
led.c
#include "led.h"
#include "stm32f10x.h"
void LED_Init(void){
RCC->APB2ENR|=1<<2;
RCC->APB2ENR|=1<<5;
//GPIOA.8
GPIOA->CRH&=0xFFFFFFF0;
GPIOA->CRH|=0x00000003;
GPIOA->ODR|=1<<8;
//GPIOD.2
GPIOD->CRL&=0xFFFFF0FF;
GPIOD->CRL|=0x00000300;
GPIOD->ODR|=1<<2;
}
(2)主函数编写
main.c
#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
int main(void)
{
delay_init();
LED_Init();
while(1){
GPIOA->ODR|=1<<8;
GPIOD->ODR|=1<<2;
delay_ms(500);
GPIOA->ODR&=~(1<<8);
GPIOD->ODR&=~(1<<2);
delay_ms(500);
}
}
5、仿真调试
Proteus 8版本的元件库中没有包括stm32系列,需要更新Proteus之后才能应用stm32元件库。
6.程序烧录
使用FlyMCU往STM32中烧写程序,正常情况下,软件会自动搜索到串口。加载之前在Keil中生成的hex文件,勾选【校验】和【编译后执行】,点击【开始编程】,烧录程序。右窗口为输出信息。
7、上板显示
8、报错处理
- (1)Device中的文件图标有红叉,需要选中右击选择更新Device版本的选项,更新一下红叉消失
- (2)Keil出现“no source“: Error: command-line: #564: cannot open,页面呈现灰色编译失败,可以尝试使用管理员身份运行keil
- (3)proteus仿真中出现以下错误
是供电网配置出错,需要更改电网连接方式,将多余网络移除GROUD连接,加至VCC/VDD连接,具体效果如下:
路径为:菜单栏->设计->配置供电网->取消“是否使用默认电路连接设置”
三、问题一
- 1、嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器—>对应相关管脚)的操作有哪些相同与差别?
相同:
变量和寄存器都通过定义来代表内存或外设中的一个地址空间,都通过相同的C语言基础语法进行编写,而且都通过变量或寄存器来实现对内存或外设的读写操作。
差别:
(1)C代码对内存修改的变量是储存在内存里的数据,由CPU直接读取和写入,速度较快;
(2)对外设的操作,操作对象是硬件,包括各种端口、时钟等,通过对各个寄存器的修改来操作速度相较于对内存来说更慢。
2、为什么51单片机的LED点灯编程要比STM32的简单?
(1)用51单片机开发通常是直接操作寄存器,指令集更简单,指令执行速度更快,操作寄存器的方式直接,因此编程易于上手;
(2)51单片机的资源占用更少,所需要的内存、存储空间和低级硬件资源更少,因此开发者可以更加专注于程序状态的处理,编写更加高效、简洁的代码;
(3)51单片机系统功能较为简单,从内部硬件到软件有一套完整的按位操作系统,处理对象是位,功能完备上手方便;
(4)STM32系列单片机内容丰富功能强大,但开发环境和编程语言相对复杂,并且STM32的寄存器数量和种类更多,需要对硬件有深入的了解和学习。
四、问题二
与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。
- register关键字告诉编译器,这个变量需要存储在寄存器中,以便能够更快地访问。通常,register关键字只适用于较小的变量,例如循环计数器或临时变量。如果编译器无法将变量存储在寄存器中,那么它会像普通变量一样存储在RAM中。
#include <stdio.h>
int main()
{
register int a = 10; //将变量 i 保存到寄存器中,可以最快速访问。
printf("a = %d\n", a);
return 0;
}
a=10 //输出
- volatile关键字告诉编译器,这个变量的值随时可能发生变化,在编译器进行优化时不应该对这个变量进行优化。这经常用于多线程编程和硬件编程中。如果不加volatile关键字,编译器可能会将一些读写变量的代码优化掉,因为编译器认为它们的值不会发生变化,但实际上这些变量的值可能被其他线程或硬件修改。
#include <stdio.h>
int main()
{
volatile int a = 10; //使用volatile来告诉编译器这个变量的值可能会被硬件自动改变。
printf("a = %d\n", a);
return 0;
}
a=10 //输出
五、总结
本次实验的内容比较多,遇到很多的环境配置问题,比如大二期间一直使用的keil 4和Proteus 8都不再适用,所以只能重新安装或者进行更新。我本来是想在Proteus 8中加入stm32的元件库,但是Proteus官网中器件模型只能单独下载,考虑到后面还需要进行很多实验,最终还是选择将软件更新到Proteus8.15版本。之后在stm32上通过寄存器方式点亮LED时,我的编译和仿真程序疯狂报错,修改一处就会出现更多的问题,可见嵌入式学习需要强大的耐心。