第二周STM32单片机编程入门作业(点亮LED)

第二周STM32单片机编程入门作业(点亮LED)

介绍

本博客记录了在安装Keil μVision5开发环境以及烧录工具mcuisp的过程,并演示了如何使用其开发一个简单的程序来通过寄存器方式点亮STM32开发板上的LED。

环境搭建
安装Proteus:
  1. 下载安装程序:前往Proteus官方网站下载最新版本的Proteus安装程序。
  2. 运行安装程序:打开下载的安装程序文件,然后运行它。
  3. 选择安装选项:在安装过程中,你可能需要选择一些安装选项,例如安装路径、组件等。根据你的需求进行选择。
  4. 等待安装完成:安装程序会将Proteus及其相关组件安装到你选择的目录中。安装过程可能需要一些时间,具体取决于你的计算机性能和安装选项。
  5. 完成安装:安装完成后,你将收到安装成功的消息。你可以选择启动Proteus,或者手动启动它。
  6. 激活许可证:输入在网上寻找Proteus的许可证信息以激活软件。按照提供的步骤进行操作。
安装Keil μVision5:
  1. 下载安装程序:从Keil官网下载μVision5安装程序。

  2. 运行安装程序:运行安装程序,按照提示操作。

  3. 选择组件:选择安装μVision IDE和目标硬件支持包。

  4. 选择安装路径:选择安装文件夹。

  5. 等待完成:等待安装完成。

  6. 启动μVision5:从开始菜单或安装目录启动μVision5。

创建新项目
  1. 在Keil μVision5中,点击“Project”菜单,然后选择“New μVision Project”。

  2. 在弹出的对话框中,输入项目名称,选择存储项目的目录,并选择目标设备(例如本篇使用为STM32F103C8)。

  3. 点击“OK”创建新项目。

    在这里插入图片描述

编写程序

在MDK5中,可以使用C/C++编写STM32程序。以下是本次实验所用代码,演示如何通过寄存器方式点亮STM32F103C8开发板所连接的三个LED灯。

#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800

#define RCC_APB2ENR (*(unsigned int *)0x40021018)

#define GPIOB_CRL (*(unsigned int *)0x40010C00)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)

#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
	
void SystemInit(void);
void Delay_ms(volatile  unsigned  int);

void Delay_ms( volatile  unsigned  int  t)
{
     unsigned  int  i;
     while(t--)
         for (i=0;i<800;i++);
}

int main(){
	RCC_APB2ENR |= (1<<3); 
	RCC_APB2ENR |= (1<<4); 
	RCC_APB2ENR |= (1<<2); 
	
	GPIOB_CRL &=0xfffffff0 ;
	GPIOB_CRL |= 0x00000001;
	GPIOC_CRH &= 0x0fffffff; 
	GPIOC_CRH |= 0x30000000;
	GPIOA_CRL &= 0xfffffff0;
	GPIOA_CRL |= 0x00000001;

	GPIOB_ODR |= (1<<0);
	GPIOC_ODR |= (1<<15);
	GPIOA_ODR |= (1<<0);
	
	
	while(1){
		GPIOB_ODR =0x0<<0;
		Delay_ms(1000);
		GPIOB_ODR =0x1<<0 ;
		Delay_ms(1000);
		
		GPIOC_ODR =0x0<<15;
		Delay_ms(1000);
		GPIOC_ODR =0x1<<15;
		Delay_ms(1000);
		
		GPIOA_ODR =0x0<<0;
		Delay_ms(1000);
		GPIOA_ODR =0x1<<0;
		Delay_ms(1000);
		
	}
}
void SystemInit(){
	
}

组装开发板

通过Proteus的仿真如下
在这里插入图片描述

对于USB转TTL模块stm32f103c8t6连接

  • GNDGND

  • 3v33v3

  • TXDA10

  • RXDA9

  • 在这里插入图片描述

    以下为总电路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

编译和下载
  1. 在Keil中,点击“Project”菜单,选择Option for Target ‘Target 1’,并勾选Output菜单中的Create HEX File选项,点击OK,保存并返回主界面

    在这里插入图片描述

  2. 在Keil中,点击“Build”以编译项目。

    在这里插入图片描述

  3. 连接开发板与PC主机

  4. 打开软件mcuisp,在STMISP菜单中,准备上传HEX文件stm32f103c8t6

    填写HEX文件的地址,如图进行勾选后,点击读器件信息后,点击开始编程,开始进行烧录

    在这里插入图片描述

  5. 最后成功实现流水灯

流水灯交替闪烁

思考

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

2)为什么51单片机的LED点灯编程要比STM32的简单?

3)与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。

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

相同点:

  • 访问内存变量和外部设备寄存器都需要使用相应的地址或寄存器名。
  • 对变量和寄存器的读写操作都需要考虑并发性和原子性,以防止数据冲突和意外的副作用。
  • 在C程序中,使用相似的语法进行变量和寄存器的读写操作,通常使用赋值操作符(=)。

差异点:

  • 内存变量通常是在RAM中分配的,可以通过指针进行间接访问,而外部设备的寄存器通常是硬件特定的,需要通过直接内存访问(Direct Memory Access,DMA)或特殊的寄存器操作指令来访问。
  • 外部设备寄存器的访问可能需要特殊的寄存器映射表和位操作,以设置或清除特定位的值,而内存变量的访问通常只涉及读写整个变量。
  • 内存变量通常受C编译器的管理,可以使用标准的C语法进行操作,而外部设备的寄存器通常需要特定的硬件抽象层(Hardware Abstraction Layer,HAL)或低级编程来进行配置和操作。
2)为什么51单片机的LED点灯编程要比STM32的简单?

这个问题的答案涉及到不同芯片架构和外设设计的差异:

  • 芯片架构:51单片机通常使用基于经典的8位MCU架构,而STM32系列芯片采用了更现代的32位ARM Cortex-M架构。32位架构具有更强大的性能和功能,但也需要更多的配置和管理。因此,在某些方面,51单片机可能更简单,因为它们通常用于较简单的任务。

  • GPIO控制:在51单片机中,GPIO控制通常更加简单,因为它们通常只有少量的GPIO引脚,并且对这些引脚的控制是直接的,不需要复杂的初始化或配置。而STM32系列芯片具有更多的GPIO引脚,需要更复杂的初始化和配置,以满足不同的应用需求。

  • 开发环境和库:针对STM32芯片的开发通常使用HAL库或CubeMX等工具,这些工具提供了更高级别的抽象和功能,但可能需要更多的学习和配置。而51单片机的开发通常使用较简单的开发环境和标准C语言库。

综上所述,51单片机的LED点灯编程可能会相对简单,因为它们通常用于较简单的应用,拥有较简单的硬件和开发环境。而STM32系列芯片更适合复杂的嵌入式应用,因此需要更多的配置和管理,但也提供了更大的灵活性和性能。选择芯片应基于具体的应用需求来决定。

3)与PC平台上的一般程序不同,嵌入式C程序经常会看见 register和volatile 关键字,请解释这两个变量修饰符的作用,并用C代码示例进行说明。

在嵌入式C编程中,经常会看到 registervolatile 这两个变量修饰符,它们用于告诉编译器如何对变量进行优化和访问。下面我将解释它们的作用,并提供相应的C代码示例:

  1. register 关键字:

    • register 关键字用于提示编译器将一个变量存储在CPU的寄存器中,以提高访问速度。然而,编译器不一定会遵循这个提示,因为寄存器的数量是有限的,编译器会根据情况决定是否将变量放入寄存器中。
    • 使用 register 关键字的变量不能被取地址,因为它们可能存储在寄存器中,而寄存器没有地址。

    示例代码:

    register int x;  // 声明一个寄存器变量
    x = 10;          // 可能存储在寄存器中
    int* ptr = &x;   // 错误,无法取 `x` 的地址
    
  2. volatile 关键字:

    • volatile 关键字用于告诉编译器不要对变量进行优化,因为变量的值可能会在编程语境之外被改变,例如,由硬件或其他线程/中断修改。
    • 这可以确保每次访问变量时都会从内存中读取其最新值,而不会使用缓存的值。

    示例代码:

    volatile int sensorValue;  // 使用 volatile 修饰的变量
    while (1) {
        // 假设传感器的值会在中断中更新
        int reading = sensorValue;  // 从内存中读取 sensorValue 的最新值
        // 这里进行操作,不会使用缓存的值
    }
    

总结:

  • register 提示编译器将变量存储在寄存器中,以提高访问速度,但不一定会生效。
  • volatile 告诉编译器不要对变量进行优化,以确保每次访问都会从内存中读取最新的值,适用于可能被外部因素修改的变量,如硬件寄存器。

————————————————
版权声明:本文参考自CSDN博主 Baker_Streets 的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_46628481/article/details/120800967

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值