stm32c8t6寄存器方式与标准库方式流水灯

stm32c8t6寄存器方式与标准库方式流水灯

一、寄存器流水灯

0、找寄存器地址的方法

第一步,找到GPIOB的基地址
手册中没有直接给出所有的寄存器的地址,需要读者稍加计算。STM32给不同的寄存器分配了不同的地址,有点像划分了片区。在《STM32中文参考手册_V10》的第28页,有不同寄存器的地址范围。
现在,假如我们想读取PB3引脚的电平,该怎么找到相关的寄存器?
  也就是找到GPIOB的小区。结论是,所有GPIOB相关的寄存器,都住在0x4001 0C00到0x4001 0FFF范围内

在这里插入图片描述

第二步,找到端口输入寄存器的地址偏移
找到存储数据的那个屋子,结论是0x4001 0C00+8 = 0x4001 0C08

在这里插入图片描述

第三步,找到知道数据的那个人
PB3的数据位于从右往左数第4个。

在这里插入图片描述

1、程序设计思路以及代码实现

首先要配置时钟使能。为什么配置时钟?为了省电,默认的时钟都是关闭的。配置STM32的任何资源前,都必须首先使能时钟。

(1)使能GPIO时钟(APB2外设时钟使能寄存器)

在这里插入图片描述

	//打开gpio A端口的时钟
	*(unsigned int *)0x40021018 |=(1<<2);
	//打开gpio B端口的时钟
	*(unsigned int *)0x40021018 |=(1<<3);
	//打开gpio C端口的时钟
	*(unsigned int *)0x40021018 |=(1<<4);

(2)端口配置低寄存器配置输出模式

每一个端口需要四位进行配置,16个端口就需要64位进行配置,所以端口配置寄存器有两个,一个是端口配置低寄存器,一个是端口配置高寄存器,但高寄存器一般没用暂时不管

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

	//--------------APB2使能时钟寄存器------------------------
#define RCC_AP2ENR *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
//----------------GPIOA输出寄存器 ------------------------
#define GPIOA_ORD *((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 ------------------------
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
//----------------GPIOB输出寄存器 ------------------------
#define GPIOB_ORD *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
//----------------GPIOC输出寄存器 ------------------------
#define GPIOC_ORD *((unsigned volatile int*)0x4001100C)

(3)端口输入数据寄存器和端口输出数据寄存器

在这里插入图片描述

端口输入数据寄存器,低16位对应16个引脚,高16位没有用
在这里插入图片描述

端口输出数据寄存器,同样是低16位对应16个引脚,高16位没有用

 GPIOA_CRL&amp;=0x0FFFFFFF;  //清除该位原来的设置
 GPIOA_CRL|=0x20000000;  //A7推挽输出,2Mhz
 GPIOA_ORD|=0x1<<7;        //设置初始灯为灭


 GPIOB_CRH&amp;=0xFFFFFF0F;  //清除该位原来的设置
 GPIOB_CRH|=0x00000020;  //B9推挽输出,2Mhz
 GPIOB_ORD|=0x1<<9;        //设置初始灯为灭


 GPIOC_CRH&amp;=0x0FFFFFFF;  //清除该位原来的设置
 GPIOC_CRH|=0x20000000;  //C15推挽输出,50Mhz
 GPIOC_ORD|=0x1<<15;     //设置初始灯为灭

(4)实现流水灯
//函数封装
void A_LED_LIGHT(){
 GPIOA_ORD=0x0<<7;  
 GPIOB_ORD=0x1<<9;  
 //GPIOC_ORD=0x1<<15; 
 GPIOC->ODR = 0x00002000; 
}
void B_LED_LIGHT(){
 GPIOA_ORD=0x1<<7;  
 GPIOB_ORD=0x0<<9;  
 //GPIOC_ORD=0x1<<15; 
 GPIOC->ODR = 0x00002000;
	
}
void C_LED_LIGHT(){
 GPIOA_ORD=0x1<<7;  
 GPIOB_ORD=0x1<<9;  
 //GPIOC_ORD=0x0<<15;
 GPIOC->ODR = 0x00002000;
	
}
void D_LED_LIGHT(){
 GPIOA_ORD=0x1<<7;  
 GPIOB_ORD=0x1<<9;  
 //GPIOC_ORD=0x1<<15;
 GPIOC->ODR = 0x00000000; 
 	
}
//主函数
	while(1)
	{
		A_LED_LIGHT();
		Delay_ms(1000);
		B_LED_LIGHT();
		Delay_ms(1000);
		C15_LED_LIGHT();
		Delay_ms(1000);

在这里插入图片描述

二、标准库方式流水灯

0、固件库

(1)新建文件

在这里插入图片描述

(2)引入固件库

将固件库复制到library文件夹中,再添加到keil的library组中
在这里插入图片描述
在这里插入图片描述

后将这三个文件添加到User文件中

在这里插入图片描述

详情请参考江协的讲解视频,全部加完后大致如下

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

1、LED流水灯

(1)代码

通过查看各个固件文件,查找函数完成对各个接口的操作,在User组中添加延时函数。

Delay.C

//Delay.c
#include "stm32f10x.h"

/**
  * @brief  微秒级延时
  * @param  xus 延时时长,范围:0~233015
  * @retval 无
  */
void Delay_us(uint32_t xus)
{
	SysTick->LOAD = 72 * xus;				//设置定时器重装值
	SysTick->VAL = 0x00;					//清空当前计数值
	SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器
	while(!(SysTick->CTRL & 0x00010000));	//等待计数到0
	SysTick->CTRL = 0x00000004;				//关闭定时器
}

/**
  * @brief  毫秒级延时
  * @param  xms 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_ms(uint32_t xms)
{
	while(xms--)
	{
		Delay_us(1000);
	}
}
 
/**
  * @brief  秒级延时
  * @param  xs 延时时长,范围:0~4294967295
  * @retval 无
  */
void Delay_s(uint32_t xs)
{
	while(xs--)
	{
		Delay_ms(1000);
	}
} 


Delay.h

//Delay.h
#ifndef __DELAY_H
#define __DELAY_H

void Delay_us(uint32_t us);
void Delay_ms(uint32_t ms);
void Delay_s(uint32_t s);

#endif


main.c

//main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{

	//设置时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	
	//定义结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	//将输出模式设置为推挽输出
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	//输出点为a0
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
	//或使用GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 |GPIO_Pin_7;
	//输出速度为50HZ
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	//以上完成结构体GPIO_InitStructure的参数配置
	
	//用结构体完成对GPIO的配置
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_Init(GPIOB,&GPIO_InitStructure);
    GPIO_Init(GPIOC,&GPIO_InitStructure);
	while(1)
	{
		//GPIO_WritBit,对单个端口进行写入、消除控制,
		//使用GPIOx,GPIO_Pin_0-16分别表示x0至x16
		//Bit_RESET为亮灯,Bit_SET为熄灭
		
	    GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bit_RESET);
		GPIO_WriteBit(GPIOB,GPIO_Pin_9,Bit_SET);
		GPIO_WriteBit(GPIOC,GPIO_Pin_15,Bit_SET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bit_SET);
		GPIO_WriteBit(GPIOB,GPIO_Pin_9,Bit_RESET);
		GPIO_WriteBit(GPIOC,GPIO_Pin_15,Bit_SET);
		Delay_ms(500);
		
		GPIO_WriteBit(GPIOA,GPIO_Pin_7,Bit_SET);	
		GPIO_WriteBit(GPIOB,GPIO_Pin_9,Bit_SET);	
		GPIO_WriteBit(GPIOC,GPIO_Pin_15,Bit_RESET);
		Delay_ms(500);
		
	}
}



在这里插入图片描述

2、使用Keil的软件仿真逻辑分析仪功能观察管脚的时序波形

使用keil的软件仿真功能中的逻辑分析仪查看波形,从而更快地定位到问题所在,进而解决问题

(1)首先,设置options for target

在这里插入图片描述

(2)点击Debug,进入调试界面

在这里插入图片描述

(3)选择逻辑分析仪

在这里插入图片描述

(4)选择要观察的引脚

在这里插入图片描述

添加要观察的引脚

在这里插入图片描述

运行程序

在这里插入图片描述

观察波形,把光标移动到逻辑分析仪显示波形的区域,上下滚动滑轮,就可以放大和缩小波形:

在这里插入图片描述

三、实验心得

程序设计思路:需了解 STM32 的 GPIO 相关寄存器,如控制寄存器(CRL、CRH)和数据输出寄存器(ODR)。以 GPIOA 为例,其基地址 0x40010800,CRL 寄存器用于配置 PA0 - PA7 引脚,CRH 配置 PA8 - PA15 引脚,每个引脚在寄存器中占 4 位,本次实验将引脚配置为推挽输出模式。

编程难点与解决:主要难点是理解和配置寄存器,其位含义需研究数据手册。延时函数开始用简单循环计数不够精确,后通过查阅资料得知可利用定时器实现更准确延时。

工程项目创建与添加库文件:在电脑创建项目目录“STM32_LED_Project”,其下建“src”放源文件、“inc”放头文件、“lib”放标准外设库文件。从官方库中复制相关.c 和.h 文件到“lib”,在 Keil 工程中把“src”添加到源文件组、“inc”添加到头文件路径、“lib”中的.c 文件添加到工程,注意文件选择和路径设置。

观察波形分析:软件仿真逻辑分析仪可观察 GPIO 端口输出波形。未精确计算延时时间时波形周期不稳定,简单循环计数延时受 CPU 执行速度影响,实际闪烁周期与预期 1 秒有偏差。通过分析波形能理解代码对硬件的控制效果,进一步优化可使用定时器中断实现更准确延时。

硬件与软件结合:深刻体会到 STM32 开发中硬件和软件结合的重要性。理解 GPIO 寄存器配置能准确控制 LED 灯等硬件行为,这种底层控制方式加深了对嵌入式系统工作原理的理解。

编程技能提升:任务 1 的寄存器编程锻炼了直接操作硬件寄存器能力,有助于理解芯片工作机制和后续学习。任务 2 的标准外设库编程体验到库函数便利,学到添加使用库文件和组织工程文件结构的方法。

调试与问题解决能力:实验中遇到 LED 灯不闪烁、闪烁周期不正确等问题。通过使用软件仿真工具特别是逻辑分析仪功能,观察波形可快速定位问题,提高了问题解决能力和耐心。

总结与展望 本次实验意义重大,掌握了 GPIO 端口使用方法,提升了编程和调试能力。未来希望深入学习 STM32 的定时器、中断、通信接口等功能模块,并应用到复杂项目中开发实用的嵌入式系统,同时认识到嵌入式开发需持续学习和实践积累经验。

参考

https://blog.youkuaiyun.com/Xkccsdn147/article/details/133796943

https://blog.youkuaiyun.com/Morzart/article/details/133817807

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值