STM32/51单片机编程入门(点亮LED)
安装Proteus并且创建工程
连接元器件并添加网格编号
在keil中填写程序
#include <REGX52.H>
#include <INTRINS.H>
void Delay500ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
i = 4;
j = 205;
k = 187;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void main()
{
while(1)
{
P2=0xFE;//1111 1110
Delay500ms();
P2=0xFD;//1111 1101
Delay500ms();
P2=0xFB;//1111 1011
Delay500ms();
P2=0xF7;//1111 0111
Delay500ms();
P2=0xEF;//1110 1111
Delay500ms();
P2=0xDF;//1101 1111
Delay500ms();
P2=0xBF;//1011 1111
Delay500ms();
P2=0x7F;//0111 1111
Delay500ms();
}
}
编译并选择生成hex文件:
双击Proteus中的单片机,将生成hex放在Program File中:
得出的仿真结果如下
问题一
嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器—>对应相关管脚)的操作有哪些相同与差别?
解答:
嵌入式C程序代码对内存(RAM)中的变量和对外部设备(寄存器->对应管脚)的操作在以下几点有差别:
相同点:
都通过变量或寄存器来实现对内存或外设的读写操作。
变量和寄存器都通过定义来代表内存或外设中的一个地址空间。
差异点:
变量操作对象是内存中的RAM空间,寄存器操作对象是外设内部的寄存器空间。
变量操作直接影响内存中的数据,寄存器操作通过改变寄存器的值来控制外设的工作状态或数据线的电平变化。
变量地址是相对地址,寄存器地址通常是绝对物理地址,对应单片机总线上的确定端口。
变量类型限定了可读写的数据格式,寄存器根据数据手册说明对应不同功能。
变量在内存中以字或字节为单位读写,寄存器根据不同外设可能以单个bit为单位操作。
变量生命周期在程序运行期间,寄存器对应外设的工作状态在单片机上电期间。
所以总体来说,变量操作对象是内存,寄存器操作对象是外设,二者在操作目的和方法上有明显差异。
问题二
为什么51单片机的LED点灯编程要比STM32的简单?
解答:
51单片机LED点灯编程比STM32简单主要有以下几点原因:
51单片机I/O口直接连接LED,只需将口线设置为输出状态并输出高电平就可以点亮LED。而STM32需要通过外设驱动LED,增加了一层复杂度。
51单片机I/O操作直接使用单指令搞定,如SETB、CLR等。STM32需要配置外设寄存器,增加了编程难度。
51单片机没有内部外设,I/O口操作不需要外设时钟和初始化设置。STM32外设操作前需要配置时钟树、复用功能等。
51单片机资源较少,I/O口地址简单,不需要考虑资源冲突问题。STM32资源丰富,需要选择合适的I/O口和外设通道。
51单片机指令简单直观,不需要了解复杂的ARM指令集。STM32需要掌握ARM指令和寻址模式。
51单片机开发环境简单,如ISIS、Proteus等模拟器支持好。STM32需要使用IDE环境如MDK、IAR等,开发门槛较高。
51单片机例程少,例如LED点亮只需几行代码。STM32例程复杂,需要考虑更多细节问题。
所以总体来说,51单片机资源简单,I/O操作直观,开发门槛低,所以LED点亮编程难度小于STM32。STM32强大但复杂度也更高。
问题三
(理论概念-常见嵌入式岗位面试题) 与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。
解答:
register和volatile这两个变量修饰符在嵌入式C程序中使用频率很高,主要作用是:
register关键字:
用于声明自动变量,目的是告诉编译器这个变量最好分配在寄存器中存储,而不是内存,以提高访问速度。
例如:
register int i;
volatile 关键字:
1
2
用于声明那些可能由外部因素改变值的变量,禁止编译器对这些变量进行优化。
比如外设寄存器、静态变量等,它们的值可能由硬件或中断更改。
例如:
volatile unsigned int LED=0;
void main()
{
LED=1; //点亮LED
while(1);
}
1
2
3
4
5
6
void interrupt() //中断服务程序
{
LED=0; //关闭LED
}
1
2
3
4
在这个例子中:
使用register声明i变量,告诉编译器优先分配寄存器存储。
使用volatile声明LED变量,告诉编译器不要对这个变量进行优化,以保证主程序和中断程序看到的LED值一致。
所以总结来说,register用于性能优化,volatile用于解决多任务访问变量值不一致的问题。