我们在刚接触C语言时,写的第一个程序必定是hello world,其他的编程语言也是这样类似的代码是告诉我们进入了编程的世界,在单片机中也不例外,不过我们的传统就是点亮第一个LED灯,点亮电阻,电容的兄弟,也是挺厉害🤭的但是没有必要。
一、创建工程
在这一章中,我们将了解到这款芯片的初始化配置,我们参考了网上的一些资料,和沁恒官方所提供的手册和例程
如果还不了解使用这款芯片所用的软件和如何新建工程,可以去阅读专栏的前面两章阅读的地址我放在下面:
1.软件安装https://blog.csdn.net/jzkj201/article/details/140397936
2.创建工程https://blog.csdn.net/jzkj201/article/details/140443312
二、这篇文章能了解什么
我们在正式开始点亮第一个LED灯前,先了解一下读了这篇能获得什么:
- 部分GPIO库函数的解读
- GPIO的初始化
- GPIO函数的写操作
- 延迟函数
- 代码程序
2.1 部分GPIO库函数的解读
找到图片的位置我们就可以看到,这款RISC-V架构的单片机的库函数了,学过STM32标准库的小伙伴,我相信你们也可以快速读懂库函数的。
2.2 GPIO的初始化
为了方便程序的代码的管理,我新建了一个文件夹,用于放置相关代码的初始化和代码。感兴趣的小伙伴,可以自己搜索如何设置,后续我也会出相关的教材。如果现在不知道怎么创建的小伙伴,可以将初始化的代码,复制到int man()里面while函数的上面,就可以完成GPIO的初始化。
下面我们就来看看这些代码表示什么意思。
void LED_Init(){GPIO_InitTypeDef GPIO_InitStructure = {0};RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);
}
1.声明并初始化GPIO初始化结构体:
GPIO_InitTypeDef GPIO_InitStructure = {0};
GPIO_InitTypeDef 是一个结构体类型,用于存储GPIO初始化的配置参数。
GPIO_InitStructure = {0}; 将这个结构体初始化为0,以确保所有成员变量都被设置为默认值。
2.使能GPIOA的时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd() 函数用于使能或失能外设的时钟。
RCC_APB2Periph_GPIOA 是GPIOA端口的时钟。
ENABLE 参数表示使能这个时钟。使能GPIOA的时钟是必要的,因为在配置和使用GPIOA引脚之前,必须先使能它的时钟。
3.配置GPIO引脚:
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Pin_0 | GPIO_Pin_1 指定要初始化的引脚为GPIOA的引脚0和引脚1。通过使用位或运算符|,可以同时选择多个引脚。GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Mode_Out_PP 设置引脚模式为推挽输出模式。(小伙伴们可以去了解数据手册中的其他几个输出模式)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Speed_50MHz 设置引脚的速度为50MHz。速度配置决定了引脚的最大切换速度,即引脚能够多快地从高电平切换到低电平或者反之。50MHz是较高的切换速度,适用于快速开关操作。
4.调用官方的库函数:GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_Init() 函数使用上面设置的参数初始化GPIOA的引脚。GPIOA 是要初始化的GPIO端口。&GPIO_InitStructure 是一个指向结构体的指针,该结构体包含初始化参数。
通过这个函数,GPIOA的引脚0和引脚1被配置为推挽输出模式,并准备以50MHz的速度操作。这些引脚现在可以用来控制LED或者其他输出设备。
2.3 GPIO函数的写操作
初始化GPIO口后,现在就可以对LED灯进行操作,在操作前我们先看看"ch32v30x_gpio.h"中的
void GPIO_WriteBit(GPI_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);这两个函数.
GPIO_WriteBit函数
参数说明:
GPIOx
:指向GPIO端口基地址的指针,可以是GPIOA到GPIOG之一。GPIO_Pin
:要写入的端口引脚,可以是GPIO_Pin_x
,其中x
可以是0到15。BitVal
:要写入引脚的值,可以是Bit_RESET
或Bit_SET
。功能实现:
- 判断
BitVal
是否为Bit_RESET
。如果不是Bit_RESET
,即为Bit_SET
:
GPIOx->BSHR = GPIO_Pin;
将选定的引脚置位(设置为高电平)。- 否则(
BitVal
为Bit_RESET
):
GPIOx->BCR = GPIO_Pin;
将选定的引脚清零(设置为低电平)
GPIO_WriteBit函数
参数说明:
GPIOx
:指向GPIO端口基地址的指针,可以是GPIOA到GPIOG之一。PortVal
:要写入端口输出数据寄存器的值。功能实现:
GPIOx->OUTDR = PortVal;
将PortVal
的值写入到指定的GPIO端口的输出数据寄存器(OUTDR)。这会一次性地设置该端口所有引脚的状态。
2.4 延迟函数
了解GPIO写操作的相关函数后,我们就来了解一下沁恒微电子官方给我提供的一些延迟函数,方便后续的LED灯的闪烁,流水灯,跑马灯等程序的编写。有关与延迟函数的库在debug.h中
void Delay_Init(void)
void Delay_Us(uint32_t n)
void Delay_Ms(uint32_t n)
Delay_Init 函数
初始化延迟功能,计算并设置延迟计数变量。
功能:
SystemCoreClock
是系统核心时钟的频率。p_us
是系统核心时钟频率除以8000000的结果,表示每个微秒的计数值。p_ms
是每个微秒的计数值乘以1000,表示每个毫秒的计数值。
Delay_Us 函数
实现微秒级延迟。
- 清除SysTick状态寄存器的第0位。
- 计算延迟计数值
i
,等于n
(微秒数)乘以p_us
。- 将计数值
i
写入SysTick的比较寄存器(CMP)。- 设置SysTick控制寄存器:
- 第4位:使能SysTick定时器。
- 第5位和第0位:启动SysTick定时器。
- 等待直到SysTick状态寄存器的第0位被置位,表示延迟结束。
- 清除SysTick控制寄存器的第0位,停止定时器。
Delay_Ms 函数
实现毫秒级延迟。
- 清除SysTick状态寄存器的第0位。
- 计算延迟计数值
i
,等于n
(毫秒数)乘以p_ms
。- 将计数值
i
写入SysTick的比较寄存器(CMP)。- 设置SysTick控制寄存器:
- 第4位:使能SysTick定时器。
- 第5位和第0位:启动SysTick定时器。
- 等待直到SysTick状态寄存器的第0位被置位,表示延迟结束。
- 清除SysTick控制寄存器的第0位,停止定时器。
好了,我们了解了一些基本的函数,那现在就开始来写代码吧。
2.5 代码程序
int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);SystemCoreClockUpdate();Delay_Init();USART_Printf_Init(115200); printf("SystemClk:%d\r\n",SystemCoreClock);printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );printf("This is printf example\r\n");LED_Init();while(1){GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);GPIO_WriteBit(GPIOA, GPIO_Pin_1, Bit_RESET);}
}
以上这段段代码就实现了LED1和LED2的点亮,目前我并没有最main函数内的串口等相关函数进行修改,后续会根据实际情况对main函数内的函数进行精简。
Tips:为什么在给相应的GPIO置低电平的时候LED灯才会亮呢?下面我们只需要看官方给的原理图就能明白,小伙伴根据自己的原理,给出合理的电平信号,来点亮你的LED灯吧。