一、 安装并熟悉Proteus 电路仿真软件,完成一个C51程序设计和仿真
1.Proteus的简介
Proteus软件是英国Lab Center Electronics公司出版的EDA工具软件。它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。
1.1Proteus的功能:
原理布图
PCB自动或人工布线
SPICE电路仿真
1.2Proteus的特点:
革命性的特点:
互动的电路仿真
仿真处理器及其外围电路
2.Proteus的安装
安装步骤:
1.右键以管理员身份运行安装程序
2.选择安装路径,点击Next
3.点击Next
4.等待安装完成
5.点击Finish
汉化步骤:
1.找到汉化补丁文件
2.将文件移动到Proteus目录下
3.替换目标中文件
4.运行并打开软件,如图示
3.Proteus的工程创建
3.1点击新建工程,输入工程名并选择安装路径。
3.2选择“从选中的模板中创建原理图(DEFAULT)”。
3.3选择“不创建PCB布板设计”。
3.4选择实验所需的系列、Controller、编译器
3.5点击Finish,完成创建
4.配置仿真器件
4.1配置LED灯
4.2选择三个电阻并双击电阻调整电阻大小为50Ω(电阻默认为10kΩ,电流过小,LED灯可能不亮)
4.3完成接线,如下图所示
5.使用Keil5生成.hex文件
安装Keil5软件:略
5.1创建工程
(1)点击 Project → New uVision Project …
(2)工程命名
(3)选择AT89C51芯片
(4)点击“是”确认
5.2编写主程序main.c
(1)点击新建文件
(2)编写代码
#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;
delay_ms(50);
P0=0xfd;
delay_ms(50);
P0=0xfb;
delay_ms(50);
P0=0xf7;
delay_ms(50);
P0=0xef;
delay_ms(50);
P0=0xdf;
delay_ms(50);
P0=0xbf;
delay_ms(50);
P0=0x7f;
delay_ms(50);
}
}
(3)点击保存文件,并命名文件(文件名以.c结尾)
(4)右键点击 Source Group 1 ,再点击 Add Existing Files to Group “Source Group 1”…
(5)选中led.c 文件,并点击 Add 。
5.3生成.hex文件
(1)点击魔术棒
(2)在Output中勾选Creat HEX File
(3)点击编译按钮,进行编译,生成.hex文件
6.进行仿真
(1)返回Proteus软件的原理图,双击 AT89C51 芯片,选择Program File文件,选择led.hex文件。
(2)点击开始按钮
(3)调试结果
51单片机流水灯仿真
二、安装mdk5软件和stm32包,熟悉mdk开发环境,完成一个stm32的简单的通过寄存器方式,用某一个GPIO端口点亮LED等程序。
1.STM32流水灯Keil编写
1.1创建工程
(1)点击 Project → New uVision Project …
(2)工程命名
(3)选择STM32F103C8芯片
(4)本实验在添加库文件窗口无需操作,取消即可
(6)下载startup_stm32f10x_md.s作为启动文件
ST公司提供了 3 个启动文件给我们,分别用于不同容量的 STM32 芯片,这三个文件是:
startup_stm32f10x_ld.s,
startup_stm32f10x_md.s,
startup_stm32f10x_hd.s
其中,ld.s 适用于小容量 产品;md.s 适用于中等容量产品;hd 适用于大容量产品;
容量是指 FLASH 的大小:
小容量:FLASH≤32K
中容量:64K≤FLASH≤128K
大容量:256K≤FLASH
(7)将startup_stm32f10x_md.s文件复制到目录下
(8)双击Source Group 1,选择改变
文件类型为All files,选择startup_stm32f10x_md.s
(7)下载SYSTEM(寄存器版本)文件夹(此文件夹代码在STM32F10x的芯片上通用)
同时在工程文件夹下新建HARDWARE文件夹,储存代码
(8)右键Target 1,选择Manage Project Items,
(9)在Manage Project Ltems中创建并添加USER、SYSTEM、HARDWARE的组(Groups),并在SYSTEM中添加三个.c文件
在HARDWARE中添加led.c、led.h文件(Files)
(10)创建test.c文件,并将其放在USER组下
1.2修改目标设置
(1)点击魔术棒
(2)在Output中勾选Creat HEX File
(3)在C/C++中设置sys、delay、usart的i路径
1.3主要代码编写
(1)led.c
#include "led.h"
//初始化 PB1 PC4 PD8为输出口.并使能这三个口的时钟
//LED IO 初始化
void LED_Init(void)
{
RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
RCC->APB2ENR|=1<<3; //使能 PORTB 时钟
// RCC->APB2ENR|=1<<4; //使能 PORTC 时钟
// RCC->APB2ENR|=1<<5; //使能 PORTD 时钟
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
GPIOB->CRL&=0XFFFFFFF0;
GPIOB->CRL|=0X00000003;//PB.0 推挽输出
GPIOB->ODR|=1<<0; //PB.0 输出高
GPIOA->CRL&=0XFFFFFF0F;
GPIOA->CRL|=0X00000030;//PA.1 推挽输出
GPIOA->ODR|=1<<1; //PA.1 输出高
}
(2)led.h
#ifndef __LED_H
#define __LED_H
#include "sys.h"
//LED 端口定义
#define LED0 PBout(5) // DS0
#define LED1 PBout(0) // DS1
#define LED2 PAout(1) // DS2
void LED_Init(void); //初始化
#endif
(3)test.c
#include "sys.h"
#include "delay.h"
#include "led.h"
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //初始化与 LED 连接的硬件接口
while(1)
{
LED0=0;
LED1=1;
LED2=1;
delay_ms(1000);
LED0=1;
LED1=0;
LED2=1;
delay_ms(1000);
LED0=1;
LED1=1;
LED2=0;
delay_ms(1000);
}
}
1.4尝试编译
(1)出现错误
(2)右键Target,修改ARM Compiler为v5.06
(3)编译成功
2.Proteus仿真(具体步骤请参考C51程序仿真)
2.1Proteus仿真工程
2.2进行仿真
STM32流水灯仿真
3.硬件连接
3.1STM32F103C8与USB转TTL线连接
STM32F103开发板 | USB转TTL线 |
GND | GND |
PA9 | RXD |
PA10 | TXD |
3V3 | 3V3 |
3.2 LED的电路连接
LED-RED | LED-YELLOW | LED-GREEN |
电源正极 | 电源正极 | 电源正极 |
B5 | B0 | A1 |
4.烧录
4.1下载烧录软件FlyMcu或mcuisp并打开(以FlyMcu为例)
4.2设置烧录软件,并选择.hex文件
4.3完成烧录
注意:接线帽需如图接通
烧录顺利完成
5.LED流水灯实况
STM32流水灯实况
三、(理论概念-常见嵌入式岗位面试题) 通过以上实践,结合阅读
ARM、STM32技术手册,深入思考STM32F103系列芯片的地址映射和寄存器映射原理,GPIO端口的初始化设置的一般步骤。
1.寄存器简介
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据和运算结果。寄存器是存储器层次结构中的顶端,也是系统操作数据的快速途径。通常,寄存器都是以寄存器数组的方式来实现的,也可以使用单独的触发器、高速的核心存储器、薄膜存储器以及在数种机器上的其他方式来实现。根据功能的不同,寄存器可分为基本寄存器和移位寄存器两大类。
2.地址映射和寄存器映射原理
2.1地址映射原理(也叫存储器映射,内存映射)
地址映射是将物理地址空间映射到虚拟地址空间的过程。CPU通过虚拟地址来访问内存和IO设备,而实际访问的是物理地址。地址映射由硬件电路实现,如MMU(内存管理单元),操作系统也利用此技术管理进程的虚拟地址空间。
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射。如果给存储器再分配一个地址就叫存储器重映射。
2.2寄存器映射原理
寄存器映射则是将CPU内部的寄存器映射到虚拟地址空间中的特定区域,以便程序通过读写这些虚拟地址来访问寄存器。一般情况下,通过绝对地址访问内存单元较为复杂,而通过寄存器的方式来实现更加便利。
STM32 的外设地址:
3.GPIO功能介绍
GPIO(General-Purpose Input/Output)是通用输入输出引脚,它是许多微控制器和芯片组上的数字接口,可以被软件配置为输入或输出。
GPIO在连接外部设备时发挥重要作用,它们可以使用寄存器级操作进行配置和控制,因此具有灵活性和可编程性。在输入模式下,GPIO口接收外部设备产生的电信号,并将其转换为数字信号传递给处理器。在输出模式下,GPIO口将处理器输出的数字信号转换为电信号,并向外部设备发送。
GPIO还有多种工作模式,例如中断输入模式、定时器输入捕获模式、PWM输出模式、模拟输入模式等。
4.GPIO端口的初始化设置
3.1使能GPIO口的时钟:
通过RCC相关的寄存器设置相应的GPIO口时钟使能位。
3.2GPIO端口参数设置:
对GPIO端口的工作模式,端口输出数据寄存器的值进行设置;根据需求对端口的引脚速率进行设置。
5.程序编写
5.1对单个GPIO口的初始化:
使能GPIOA的时钟:
GPIO_InitTypeDef GPIO_InitStruct; //定义初始化结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能GPIOA时钟
设置工作模式、IO属性、初始化GPIO:
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //配置模式
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; //配置哪个IO口
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口速度,仅输出有效
GPIO_Init(GPIOA,&GPIO_InitStruct); //初始化GPIOA的参数为以上结构体
5.2实例
使能GPIOA的时钟:
RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
设置工作模式:
GPIOB->CRL&=0XFF0FFFFF;
GPIOB->CRL|=0X00300000;//PB.5 推挽输出
GPIOB->ODR|=1<<5; //PB.5 输出高
5.回答:
(1)嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器--->对应相关管脚)的操作有哪些相同与差别?
相同点:
- 语法:在C语言中,无论是对内存中的变量进行修改,还是对外部设备进行操作,使用的都是同样的赋值语句。
- 硬件:无论是操作内存还是操作外部设备,都需要对硬件有一定的了解。需要理解内存的地址范围,以及设备的寄存器的地址和功能。
不同点:
- 操作对象:操作内存主要是操作RAM中的变量,而操作外部设备主要是操作设备的寄存器,这些寄存器通常对应着相关的硬件管脚。
- 操作权限:在操作内存时,程序通常具有相对较大的权限,可以访问和修改大部分内存区域。但在操作外部设备时,由于硬件的限制和保护,程序可能只能访问和修改特定的寄存器。
- 速度:内存的访问速度通常比外部设备的访问速度快很多。这是因为内存的访问是电子的,而外部设备的访问可能涉及到硬件的电磁信号等复杂的过程。
- 并发性:在操作内存时,可能会涉及到多任务、多线程的并发问题。而在操作外部设备时,由于硬件的限制,可能不存在这样的问题。
- 错误处理:在操作内存时,如果出现错误(如越界访问),程序可能会崩溃或者产生不可预测的结果。而在操作外部设备时,如果出现错误(如向错误的寄存器写入数据),可能只会影响到特定的硬件的功能。
(2)为什么51单片机的LED点灯编程要比STM32的简单?
1.硬件电路简单:51单片机连接简单的LED电路,只需将LED的正极连接到单片机的某个I/O引脚,负极接地即可。这种简单的连接方式使得编程更加容易。而STM32可能需要更加复杂的电路,如使用GPIO引脚和电阻来控制LED。
2.寄存器配置简单:51单片机的寄存器较少,配置起来相对简单。而STM32具有更多的寄存器和外设,需要更多的配置工作来实现LED点灯。
四、(理论概念-常见嵌入式岗位面试题) 与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。
1.register
register
修饰符用于提示编译器,将变量存储在寄存器中,以加快访问速度。寄存器是CPU内部的一种存储设备,访问速度比内存快得多。使用register
修饰符可以减少变量的内存访问时间,提高程序的执行效率。但是,实际上是否将变量存储在寄存器中是由编译器决定的,因为现代编译器通常能够自动进行优化。
register int i;
for (i = 0; i < 10; i++) {
// 循环体
}
2.volatile
volatile
修饰符用于告诉编译器,该变量可能会被意外地修改,不要在编译优化时做出错误的假设。在嵌入式系统中,某些内存地址可能会被外部设备或硬件直接修改,而不是通过程序来修改。使用volatile
修饰符可以确保编译器不会对这些可能被意外修改的变量进行优化,以确保程序的正确性。
volatile int shared_variable;
// 某个外部设备或硬件可以直接修改shared_variable的值
五、总结
虽然51单片机的LED点灯编程相对简单,但它的功能和性能也相对较低。而STM32具有更强大的处理能力和外设,适用于更复杂的应用场景。
参考:
[1]
Proteus使用教程并仿真51程序——LED流水灯_proteus 51 仿真_网盘已清空,链接已失效的博客-优快云博客
[2]
1、Proteus仿真STM32流水灯实验例程、详细步骤。_proteus例程_学者-老栋的博客-优快云博客[
[3]
【嵌入式08】STM32F103C8T6寄存器方式借助面包板点亮LED流水灯详解_噗噗的罐子的博客-优快云博客
[4]STM32 LED实验(寄存器方式和HAL库方式) - 知乎 (zhihu.com)
[5]