STM32实战之LED循环点亮

2023-05-16

接着上一章讲。本章我们来讲一讲LED流水灯,循环点亮LED。
在LED章节有的可能没有讲到,本章会对其进行说明,尽量每个函数说一下作用。也会在最后说一下STM32的寄存器,在编程中寄存器是避免不了的东西,寄存器也是非常好理解的,就是羊肉串串成一串而已。其实对于嵌入式来说,大多数开发者都是根据官方提供的例程写的。很少只有手册让个人写的。只有做芯片底层开发的会根据,芯片的逻辑进行代码的编写。但是对于很多开发者来说,都是基于官方提供的芯片demo进行相关的底层配置与开发。
而我们要写的主要是应用层和一些模块底层的开发。而且多数的外设模块都有代码例程,即使没有文档也是较为清楚的。什么样的没有代码的,就是新出的芯片或者传感器,笔者做过恩智浦的一款新出的包括近期做一个芯驰的开发。网上资料少得可怜,只能参考官方例程。特别是芯驰的是去年10月份刚出的,他们的东西会出现各种问题,网上找不到,但是你也不要慌,他们会提供技术支持的,会告诉你怎么做。这些新出的东西,遇到了不要觉得是自己的问题,有可能是他们芯片或者demo的问题,就像近期做芯驰的开发板demo,调试,只有静置一段时间才可以(就是断电,全部断掉,等一会,这就是他们的问题),所以遇到问题不要怕。
对了,我写实战是根据F1的,和F4的本质都差不多。

1-配置

static void Led_Cofig(void)
{
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef GPIO_InitStructure;
    /*开启LED相关的GPIO外设时钟*/
    RCC_APB2PeriphClockCmd(LED_GPIO_CLCK, ENABLE);
    /*选择要控制的GPIO引脚*/
    GPIO_InitStructure.GPIO_Pin = (LED1_GPIO_PIN | LED2_GPIO_PIN | LED3_GPIO_PIN | LED4_GPIO_PIN | LED5_GPIO_PIN | LED6_GPIO_PIN | LED7_GPIO_PIN | LED8_GPIO_PIN);
    /*设置引脚模式为通用推挽输出*/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    /*设置引脚速率为50MHz */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //(指的是内部驱动电路的响应速度,速度越大越快,一般情况是有多个不同的速度,也可根据自己的需要安排)
    GPIO_Init(LED_GPIO_PORT, &GPIO_InitStructure);
    /* 关闭led灯	*/
    GPIO_SetBits(LED_GPIO_PORT, LED1_GPIO_PIN | LED2_GPIO_PIN | LED3_GPIO_PIN | LED4_GPIO_PIN | LED5_GPIO_PIN | LED6_GPIO_PIN | LED7_GPIO_PIN | LED8_GPIO_PIN);
}

1.1 RCC_APB2PeriphClockCmd()函数

RCC_APB2PeriphClockCmd()函数的功能是使能GPIOx对应的外设时钟,若使能GPIOC时钟,对应的代码如下:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);

RCC_APB2Periph_GPIOC是在stm32f10x_rcc.h头文件中定义的。RCC_APB2Periph_GPIOA~RCC_APB2Periph_GPIOG定义的代码如下:

#define RCC_APB2Periph_GPIOA      ((uint32_t)0x00000004)
#define RCC_APB2Periph_GPIOB      ((uint32_t)0x00000008) 
#define RCC_APB2Periph_GPIOC      ((uint32_t)0x00000010) 
#define RCC_APB2Periph_GPIOD      ((uint32_t)0x00000020) 
#define RCC_APB2Periph_GPIOE      ((uint32_t)0x00000040) 
#define RCC_APB2Periph_GPIOF      ((uint32_t)0x00000080) 
#define RCC_APB2Periph_GPIOG      ((uint32_t)0x00000100)

1.2 GPIO_Init()函数

GPIO_Init()函数的功能是初始化(配置)GPIO的模式和速度,也就是设置相应GPIO的CRL和CRH寄存器值。函数原型如下所示:

GPIO_Init()函数的功能是初始化(配置)GPIO的模式和速度,也就是设置相应GPIO的CRL和CRH寄存器值。

第一个参数是GPIO_TypeDef类型指针变量,用于确定是哪一个GPIO,GPIOx取值是GPIOA~GPIOG;第二个参数是GPIO_InitTypeDef类型指针变量,用于确定GPIOx的对应引脚以及该引脚的模式和速度等。

1.3 GPIO_ReadInputDataBit ()函数

GPIO_ReadInputDataBit ()函数的功能是读取指定I/O口的对应引脚值,也就是读取IDR(在下面会介绍)寄存器的值。函数原型是:

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

第一个参数同GPIO_Init()函数一样,第二个参数是读取GPIOx的对应引脚值。如读取GPIO6(即PC6)引脚代码是:

GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_6);

1.4 GPIO_ReadInputData ()函数

GPIO_ReadInputData()函数的功能是读取指定I/O口16个引脚的输入值,也是读取IDR寄存器的值。函数原型如下:

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

比如读取GPIOC输入端的值:

tem=GPIO_ReadInputData(GPIOC);
但是如果采用寄存器的话就是:
tem=GPIOC->IDR

1.5 GPIO_ReadOutputDataBit ()和GPIO_ReadOutputData ()函数对比

这两个函数从字面就能知道一个是对单独的IO进行操作,一个是对多个IO进行操作,下面就对这两个进行分析。

//读取GPIO某个引脚的特定输出值。
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

例如:读取GPIOC中PC6的值
GPIO_ReadOutputDataBit(GPIOC.GPIO_Pin_6);
//读取GPIO端口指定组的值。
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
比如读取GPIOC的值:
GPIO_ReadOutputData( GPIOC);

1.6 GPIO_SetBits ()和GPIO_ResetBits ()函数

上一章已经说过了,本章不在多说。
函数GPIO_SetBits ()和GPIO_ResetBits ()的功能是用来设置指定I/O口的引脚输出高电平和低电平,也就是设置寄存器BSRR、BRR的值。

1.7 GPIO_WriteBit ()和GPIO_Write ()函数

这两个函数和1.5的类型是一样的。非别是对单个IO和一组IO控制,后面遇到这样的不在赘述,默认大家都知道。
GPIO_WriteBit ()函数的功能是向指定I/O口的引脚写0或者写1,也就是向寄存器ODR相应位写0或者写1。函数原型如下:

void GPIO_WriteBit(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin, BitAction BitVal);

GPIO_Write()函数的功能是向指定I/O口写数据,也就是向寄存器ODR写数据。函数原型如下:

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

举例:

//向PC6写入1
GPIO_WriteBit(GPIOC, GPIO_Pin_6, 1);
//向GPIOC写入 0x0FFFC
GPIO_Write(GPIOC, 0x0FFFC);

在这里需要注意一点:
GPIO_WriteBit()函数是对I/O口的一个引脚进行写操作,可以是写0或者写1;
GPIO_SetBits()函数可以对I/O口的多个引脚同时进行置位。
这点大家一定要知道。

GPIO_WriteBit(GPIOC,GPIO_Pin_8 , 0);             //只能对一个引脚置0或置1
GPIO_SetBits(GPIOC, GPIO_Pin_2 | GPIO_Pin_4);    //可以同时对多个引脚置1

``

2 循环点亮LED

我设计的是8个流水灯,采用共阳极的接法,与PC1~7相连接。因为32不像51有移位控制语句。
先来看代码吧,这可以说是非常基础的了,为了方便大家理解。

void LED_Cycle(void)
{
    uint16_t temp, i;
    temp = 0x01;
    for (i = 0; i < 8; i++)
    {
        GPIO_Write(LED_GPIO_PORT, ~temp);
        Delay(300);
        temp = temp << 1;
    }
    for (i = 0; i < 8; i++)
    {
        GPIO_Write(LED_GPIO_PORT, ~temp);
        Delay(300);
        temp = temp >> 1;
    }
}

首先我们从GPIOC0开始点亮这样一直循环下去:PC0点亮此位为0,依次类推如下:

PC0亮:PC输出 0x0001,取反为0xFFFE,控制码就是0xFFFE
PC1亮:PC输出 0x0002,取反为0xFFFD,控制码就是0xFFFD
PC2亮:PC输出 0x0004,取反为0xFFFB,控制码就是0xFFFB
PC3亮:PC输出 0x0008,取反为0xFFF7,控制码就是0xFFF7
PC4亮:PC输出 0x0010,取反为0xFFEF,控制码就是0xFFEF
PC5亮:PC输出 0x0020,取反为0xFFDF,控制码就是0xFFDF
PC6亮:PC输出 0x0040,取反为0xFFBF,控制码就是0xFFBF
PC7亮:PC输出 0x0080,取反为0xFF7F,控制码就是0xFF7F
然后重复执行。

根据上面的,只需将控制码从GPIOC输出即可。怎样输出呢,就是出事一位为高然后进行取反操作,在对其进行移位,然后进行循环操作(方法不止这一种,可尝试其他方式)。
“GPIO_Write(GPIOC,~temp);”语句将初始控制码0x0001取反(也就是0xFFFE)后,从GPIOC口输出,使得PC为低电平,点亮PC0,其他位为高电平;然后延时一段时间;让控制码移位,获得下一个控制码;然后再对控制码取反后输出到GPIOC口,就这样依次进行。

主函数

int main()
{
  LED_Init();
  while (1)
  {
    LED_Cycle();
  }
}

今天太晚了,哪天腾出一章用来写各个寄存器,本来是想和库函数穿插这说的。又考虑到,有些人对寄存器不太熟悉,穿插着对其不太友好。今天就到这了,喜欢就动动手一键三连,谢谢。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32实战之LED循环点亮 的相关文章

随机推荐