51单片机和stm32单片机的点灯操作

本文详细介绍了使用Proteus模拟51单片机工程并实现实时光流灯,以及使用keil5MDK通过寄存器控制STM32点亮LED灯的过程。对比了两种平台在内存操作和硬件配置上的异同,同时解析了register和volatile关键字在嵌入式C中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.使用Proteus仿真软件创建51单片机工程并运行

1.1安装Proteus仿真软件

首先我们下载Proteus仿真软件 点击下载
提取码:zmcd
下载完成之后,我们将压缩包解压得到以下文件
在这里插入图片描述
我们点击下面的.exe文件运行,出现如下界面
在这里插入图片描述

这里选择合适的安装路经进行安装,点击Next
在这里插入图片描述
点击Next开始安装
安装完成以后桌面出现以下图标
在这里插入图片描述
点击打开,Proteus安装完成
点击进入汉化补丁
在这里插入图片描述
复制上面的文件,进入Proteus安装目录
将安装目录中的此文件夹替换成我们复制的文件夹
在这里插入图片描述
重启软件,汉化完成
在这里插入图片描述

1.2创建一个51单片机的仿真模拟工程

首先创建一个新的工程,具体细节见大佬的博客
创建工程流程
工程创建完成之后,在固件库搜索AT89C51 芯片放置于原理图中
在这里插入图片描述
接下来我们放置LED灯,在右侧的固件库中搜索 LED-YELLOW,点击选中LED灯,顺时针旋转元件,将8个LED灯摆放成如下图的模样,放置电阻,将电阻值从10k改为300,以便等可以亮起来,接下来链接管脚,电源
在这里插入图片描述
一个51单片机的流水灯原理图就创建好了

1.3 编写程序

接下来我们打开keil软件,创建一个新的工程

在这里插入图片描述
选择合适的文件夹存放工程文件
在这里插入图片描述
进入下面界面,下拉选择第二个
在这里插入图片描述
接下来在搜索框中输入搜索选中AT89C51芯片
在这里插入图片描述
点击ok,完成工程的创建
接下来我们新建一个main.c文件
在这里插入图片描述
复制以下代码


```c

	#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);
		}
	}

``

将文件保存为main.c文件
在这里插入图片描述
接下来生成.hex文件
点击魔术棒,勾选Create HEX file 选项
在这里插入图片描述
点击Group1选择添加新项目,将我们刚刚编写的main.c文件导入
在这里插入图片描述
接下来点击编译,main.c文件下自动生成两个文件
在这里插入图片描述

1.4 开始仿真

接下来我们回到Proteus软件,点击51芯片,弹出以下界面,选择我们刚刚创建的.hex文件导入
在这里插入图片描述
确定导入之后运行,一个51流水灯的程序就运行成功了
在这里插入图片描述

2.使用keil5 MDK 通过寄存器方式点亮STM32LED灯

2.1 安装keil5 MDK

安装文章推荐
点击跳转

2.2 创建一个stm32工程并开始编码

关于如何创建一个stm32工程,网上很多教程,由于篇幅原因,在这里不过多的赘述了,推荐大佬文章点击跳转
工程创建完成之后进入以下界面
在这里插入图片描述

2.3查找手册配置寄存器

接下来我们需要去stm32的手册查找寄存器的地址等信息
在这里插入图片描述

我们可以看到,要点亮PC13口的LED灯,我们需要配置总线AHB的使能时钟
要配置AHB的时钟,我们需要找到AHB的起始地址
在这里插入图片描述
左边是起始地址,右边是终止地址
然后我们找APB2外设使能时钟寄存器的偏移地址,复制偏移地址,加上面AHB的寄存器时钟地址,得到0x40021018,这个地址,然后我们配置CPIOC的使能时钟,先把刚才的地址置“1”后进行位操作(移动4位),就可以得到时钟C的地址,然后我们通过强制转化将其转化为指针类型,在进行取地址的操作
在这里插入图片描述

在这里插入图片描述
接下来和上面一样,我们找到GPIOC13口的起始地址
在这里插入图片描述
接下来我们配置GPIOC13口
因为我们配置的是GPIOC13口是高配置,查找手册
在这里插入图片描述
所以要选择GPIOP以10MHz推免输出,即0x0010,再位操作20位,及以下代码
在这里插入图片描述
接下来我们配置GPIOC13的低电平
查找手册
在这里插入图片描述
通过上述手册我们可以看到偏移地址是0ch,即端口输出数据寄存器地址为 0x4001 1000+0ch=0x4001 100c
得到以上信息我们可以得到如下代码
在这里插入图片描述

2.4编译烧录代码并查看结果

查找完我们需要的信息之后我们可以得到如下三行代码
在这里插入图片描述
点击编译,0报错,0警告,点击烧录,开始烧录程序
在这里插入图片描述
未开启PC13口led
在这里插入图片描述

程序烧录成功,开启PC13口LED
在这里插入图片描述

这样我们就完成了一个stm32程序寄存器点灯的操作

3.嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器—>对应相关管脚)的操作有哪些相同与差别?

嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器—>对应相关管脚)的操作有以下相同和差别:

相同点:

  1. 两者都是通过对存储单元进行读写操作来实现数据的修改。
  2. 在C语言中,无论是对内存变量还是对外部设备寄存器,都可以使用类似的语法进行操作,例如“*”、“&”等指针运算符。

不同点:

  1. 存储空间不同:内存变量存储在RAM中,而外部设备寄存器通常存储在特定的地址空间中,如I/O空间或内存映射I/O空间。
  2. 存取速度不同:对内存变量的访问速度通常比对外部设备寄存器的访问速度快。
  3. 操作方式不同:对内存变量的操作可以通过指针或数组等方式进行,而对外部设备寄存器的操作通常需要使用特定的函数或指令。
  4. 中断和异常处理:对外部设备的操作可能会引起中断或异常,需要特殊的处理机制来处理这些情况,而对内存变量的操作通常不会。
  5. 物理实现不同:内存变量是存储在半导体材料上的电荷,而外部设备寄存器是通过电路中的电子流动来实现数据的存储和传输。

总的来说,虽然对内存变量和外部设备寄存器的操作在语法上类似,但在实际应用中存在许多差异,需要根据具体情况进行选择和操作。

3.1简述为什么51单片机点灯比STM32简单

51单片机和STM32在LED点灯编程上的难度差异主要来源于它们的硬件结构、指令集和可用资源。

  1. 硬件结构和指令集:51单片机是一种比较老的单片机,硬件结构相对简单,指令集也比较基础。这使得51单片机的编程,包括LED点灯,相对简单。而STM32是一种高级的单片机,硬件结构复杂,指令集丰富,这使得STM32的编程难度相对较高。
  2. 可用资源:51单片机通常具有较少的内存和I/O口,这意味着在51单片机上进行LED点灯编程时,你通常只需要操作少量的寄存器。而STM32通常有大量的内存和I/O口,这使得在STM32上进行LED点灯编程时,你可能需要操作更多的寄存器,或者需要考虑更多的配置问题。
  3. 库函数和开发环境:对于STM32,通常使用HAL库(硬件抽象层库)进行开发。HAL库提供了许多高级的抽象和功能,使得编程更加复杂。而对于51单片机,通常使用更基础的C语言库进行开发,这使得编程更加简单。

总的来说,51单片机的LED点灯编程比STM32的简单主要是因为51单片机的硬件结构、指令集和可用资源都比STM32的简单。

4 .解释 register和volatile 关键字

在嵌入式C程序中,register和volatile都是C语言的关键字,它们对于优化代码以及处理硬件的特定行为有着非常重要的作用。

  1. register关键字:在C语言中,register关键字用于提示编译器,该变量可能会频繁地使用,因此,可以尽可能地将其保存在寄存器中,以提高访问速度。但是,实际上是否将其保存在寄存器中是由编译器决定的,因为在现代编译器中,通常已经能够进行高度优化。

例如:

register int i;
for(i=0; i<100; i++) {
    // do something...
}

在这个例子中,i被声明为register变量,可能会被编译器优化并保存在寄存器中,以提高循环的速度。
2. volatile关键字:在嵌入式编程中,volatile关键字是非常重要的。它告诉编译器,该变量可能会被意外(即编译器无法预知的)地改变。这通常发生在硬件寄存器映射到内存的情况中,硬件的状态可能会在任何时候改变,而编译器可能认为这些变量的值没有改变,从而进行优化,导致程序出错。

例如:

volatile int *p = (volatile int*) 0x8000; // 假设0x8000是某个硬件寄存器的地址
*p = 1; // 对硬件进行写操作
int x = *p; // 从硬件读取数据

在这个例子中,p是一个指向volatile变量的指针,这意味着编译器不会对其进行优化,每次访问*p都会直接从硬件读取数据,而不是从缓存中读取。

以上是在嵌入式C程序中经常看到register和volatile关键字的原因和用法。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值