Keil4与Proteus联合仿真实现流水灯实验&&STM32实现通过寄存器实现流水灯

一、proteus安装使用

左击元件列表窗内的 AT89C51 芯片,然后再原理图编辑窗口内左击摆放,再摆放LED-YELLOW 和8个电阻。

连线,编号。

代码:

仿真:

仿真结果:

二、1.安装keil5

 keil5安装教程_Matcha_ice_cream的博客-CSDN博客

1.STM32流水灯Keil编写
1.1创建工程
(1)点击 Project → New uVision Project …

(2)选择STM32F103C8芯片

(3)下载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

(4)将startup_stm32f10x_md.s文件复制到目录下

(5)下载SYSTEM(寄存器版本)文件夹(此文件夹代码在STM32F10x的芯片上通用)

同时在工程文件夹下新建HARDWARE文件夹,储存代码

(6)在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)

​
#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)

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

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

编译成功

4、烧录:STM32F103C8T6与PC端连接

打开C8T6数据手册,查找TXD和RXD管脚位置
PA9——TX
PA10——RX

将boot0设为1,boot1设为0,利用跳线帽实现

借助FLYMCU下载软件,即可将light.hex载入

烧录成功。

 4. 思考
    1. 嵌入式C程序代码对内存(RAM)中的各变量的修改操作,与对外部设备(寄存器--->对应相关管脚)的操作有哪些相同与差别?
      对外部的设备操作是通过找到寄存器地址,然后修改寄存器的值,从而修改外部设备的状态,一般可以通过宏定义一个指针,指向寄存器的地址:

 对内存的修改操作也可以通过指针变量的方式进行修改。

     寄存器是CPU内部的组成部分,通过内部总线与CPU直接相连,内存是通过外部地址总线与C        PU相连,通过外部总线寻址,通过寄存器修改变量的值比内存更快。

     

  2. 为什么51单片机的LED点灯编程要比STM32的简单?
       因此在GPIO端口配置的时候,需要时钟信号来使能D触发器(寄存器),从而修改端口状态

       51单片机的时钟只有一个,且没有进行分频等操作

       将STM32虽然也只有一个系统时钟,但是可以通过分频,将APB1或者APB2的时钟时钟频率           更改,比51单片机多一个分频的操作,所以在开始修改寄存器时,51单片机直接能对寄存器           进行操作,而stm32则需要进行时钟配置使能。

       此外,stm32是32位单片机,而51是位8单片机,stm32能够实现的功能能多,也就意味着其更         复杂。

四、嵌入式register、volatile 关键字的作用
1. register关键字
     register声明的变量直接存在在CPU的寄存器中,程序可以直接对该变量进行读写。访问内存的变量比访问寄存器的变量更慢,因此将需要快速访问的变量放入寄存器能提高程序的效率。

for(int i=0;i<=100000000;i++)
{
 
 
 
 
}
 
for(register int i=0;i<100000000;i++)
{
 
 
 
}

这里访问了变量i很多次,如果把i定义在内存中,那么CPU每次都会从内存中访问i,这样相比在寄存器中就会很慢;如果把i用 register关键字修饰,那么访问CPU就会通过寄存器的方式访问它,从而能提高程序运行的效率。

2. volatile关键字
  volatile声明的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者其他线程,    遇到这个关键字声明的变量,编译器对访问改变量的代码不在进行优化,从而可以提供对特殊地    址的访问。每次使用它的时候必须从内存中取出它的值,不会从寄存器中使用,从而保证了对某    特殊地址的稳定访问。

 在嵌入式开发中,往往在宏定义的时候会看到这样的代码:
 

#define GPIOB_BASE ((unsigned int)0x40010800)

这样的好处便是在嵌入式编程中,硬件寄存器和内存映射设备常常需要使用volatile关键字,以确保编译器不会对其进行优化,从而保证与硬件的交互是准确的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值