上几节,我们讲解了如何移植SDK库,并且如何使用BSP工程管理,使得能够规范的管理我们的工程文件,这一讲,我们就使用前面的方法,来编写IMX6uL开发板上的蜂鸣器实验
创建一个工程文件,然后还是按照之前的方法,在根目录下创建四个文件夹,BSP、IMX6ul、OBJ、project,这四个第一级文件夹存放对应的不同文件在BSP下方新建需要完成此次实验需要的驱动,beep用来编写蜂鸣器的驱动,clk用来编写时钟驱动、delay编写延时函数、led编写LED驱动。除了beep驱动需要我们手动编写以外,其余的驱动都可以参考博主的前一篇文章来进行移植,原理这里也不过多讲解。
然后先将我们的SDK库文件移植过来,我们需要在cc.h中添加一个宏定义,后面写代码的时候需要使用到switch语句
#define ON 1
#define OFF 0
BSP的文件构造如下
下面就是每个文件的代码,原理的话参考博主的使用官方SDK库编写IMX6UL的LED灯驱动(超详细原理分析)-优快云博客
// bsp_clk.h
#ifndef __BSP_CLK_H
#define __BSP_CLK_H
#include "imx6ul.h"
void clk_init();
#endif
// bsp_clk.c
#include "bsp_clk.h"
void clk_init()
{
CCM->CCGR0 = 0xFFFFFFFF;
CCM->CCGR1 = 0XFFFFFFFF;
CCM->CCGR2 = 0XFFFFFFFF;
CCM->CCGR3 = 0XFFFFFFFF;
CCM->CCGR4 = 0xFFFFFFFF;
CCM->CCGR5 = 0XFFFFFFFF;
CCM->CCGR6 = 0XFFFFFFFF;
}
延时驱动
// bsp_delay.h
#ifndef __BSP_DELAY_H
#define __BSP_DELAY_H
#include "imx6ul.h"
void delay(volatile unsigned int n);
#endif
// bsp_delay.c
#include "bsp_delay.h"
void delay_short(volatile unsigned int n)
{
while(n--){}
}
void delay(volatile unsigned int n)
{
while (n--)
{
delay_short(0x7ff);
}
}
LED驱动
// bsp_led.h
#ifndef __BSP_LED_H
#define __BSP_LED_H
#include "imx6ul.h"
void led_init(void);
void led_on(void);
void led_off(void);
#endif
// bsp_led.c
#include "bsp_led.h"
void led_init(void)
{
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03 , 0); /*复用引脚GPIO1_IO03*/
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03 , 0X10B0); /*初始化电气属性*/
/*初始化引脚GPIO1_IO03为输出引脚,GPIOx_GDIR控制输入输出模式*/
GPIO1->GDIR |= (1<<3);
/*GPIOx_DR控制引脚的高低电平,输出低电平打开LED*/
GPIO1->DR &= ~(1<<3);
}
void led_on(void)
{
GPIO1->DR &= ~(1<<3);
}
void led_off(void)
{
GPIO1->DR |= (1<<3);
}
接下来我们开始编写蜂鸣器的驱动,首先我们还是需要看IMX6UL的原理图,首先蜂鸣器英文名称为BEEP,打开原理图ctrl + f 打开搜索框,直接搜索beep,就可以看到蜂鸣器接在了一个名字叫做SNVS_TAMPER1的标识符上,一般来说引脚标识符还有助于实现引脚的复用。在嵌入式系统中,由于引脚资源有限,因此经常需要复用引脚来实现不同的功能。使用引脚标识符可以更容易地管理这些复用情况,并确保在不同配置下引脚的功能得到正确实现。
并且能够发现这是一个三极管,我们给入高点平就可以使蜂鸣器被使能
首先先写好蜂鸣器驱动的头文件
// bsp_beep.h
#ifndef __BSP_BEEP_H
#define __BSP_BEEP_H
#include "imx6ul.h"
/*函数初始化*/
void beep_init();
void beep_switch(int status);
#endif
那么知道了引脚标识符过后,我们去参考手册当中查找它是复用的哪个引脚,这个就是此引脚标识符的寄存器,下方我们可以看到复用的引脚是GPIO5_IO01,这个是引脚复用的寄存器
那么接下来我们就可以编写初始化函数了, IOMUXC_SetPinMux()这个依然是SDK库中用来设置引脚复用的函数,目前我们知道了复用的引脚是GPIO5_IO01,知道了是哪个函数,但是如何确定函数里面参数该如何填写呢
打开SDK库中的fsl_iomuxc.h,然后依然是CTRL + F就可以打开我们的搜索框,搜索GPIO5_IO01,就可以看到跳转到SDK库中宏定义好的参数
将这个宏定义参数直接填写到函数中即可,然后后面的直接填入0,简单来讲这个0可以使得我们前面的宏定义参数不变,设计底层的封装原理这里不深入讲解。
void beep_init()
{
IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0);
IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0X01B0);
GPIO5->GDIR |= (1<<1);
GPIO5->DR |= (1 << 1);
}
然后IOMUXC_SetPinConfig()这个参数用于设置我们引脚的电气属性,使用的依然是和SNVS_TAMPER1有关的寄存器,所以里面的参数还是填入GPIO5_IO01的宏定义参数,至于为什么后面的参数为什么填入0X01B0,还是可以参考一下这篇文章,因为这个参数是设置了寄存器的各个位,然后将值转换为了16进制,原理博主在这篇文章中详细讲解过
使用官方SDK库编写IMX6UL的LED灯驱动(超详细原理分析)-优快云博客https://blog.youkuaiyun.com/Hetertopia/article/details/140988372 GPIO5->GDIR |= (1<<1); GPIO5->DR &= ~(1<<1); 在文章中也提到过,这里简单讲解一下,首先GPIO5->GDIR |= (1<<1);这个寄存器用于设置引脚为输出还是输入,这里IO01且要将1位设置为1,所以采用位运算的方式,|= (1<<1)就可以得到我们想要的结果
那么 GPIO5->DR &= ~(1<<1);也是一样,因为下方GPIOx_DR的寄存器用于设置引脚是输出高点平还是低电平,为了不让蜂鸣器打开就开始叫太吵了,所以我们需要默认将他关闭,那么就给入低电平,通过位运算将IO1第一位,置1那么蜂鸣器就被初始化为关闭,初始化函数就已经完成了
接下来编写如何控制蜂鸣器使能的函数,这个switch非常的简单,如果我的参数写入的是ON那么就符合第一个判断语句,执行 GPIO5->DR &= ~(1<<1);这个位运算,控制的也是DR寄存器,这里就是拉高它的电平,让它使能,也就是如果是beep_swtich(ON)那就说明蜂鸣器被使能。
如果写入参数off,那就执行else if中的代码, GPIO5->DR |= (1<<1);是这个DR寄存器输出低电平,让蜂鸣器不使能,这个就是蜂鸣器控制函数也完成了
// bsp_beep.c
void beep_switch(int status)
{
if(status == ON)
{
GPIO5->DR &= ~(1<<1);
}
else if(status == OFF)
{
GPIO5->DR |= (1<<1);
}
}
接下来就开始编写主函数,首先就是引入编写好的所有驱动头文件,然后主函数当中将初始化函数写入,进行对于各个外设的初始化,实验效果就是LED灯亮,蜂鸣器就使能,LED熄灭,蜂鸣器也关闭,所以写一个while循环,在里面写入这样的逻辑顺序,我们的代码就全部完成了
#include "imx6ul.h"
#include "bsp_clk.h"
#include "bsp_delay.h"
#include "bsp_led.h"
#include "bsp_beep.h"
int main()
{
clk_init();
led_init();
beep_init();
while(1)
{
led_on();
beep_switch(ON);
delay(1000);
led_off();
beep_switch(OFF);
delay(1000);
}
return 0;
}
最后需要完成的步骤就是需要修改一下Makefile文件,因为这一次我们重新添加了蜂鸣器的驱动,首先修改的是Target因为文件名称改成了beep,然后下面的文件路径新添加一个bsp/beep也就是蜂鸣器的文件路径就完成了
至于这个Makefile为什么这么改就行了,可以参考一下前一篇对于Makefile的原理的讲解,这里就不讲解了,因为确实太繁琐了
所有的代码就编写完成了,然后最后将代码编译后,通过读卡器将代码烧写进SD卡就可以了
最后这里附上整个文件格式,方便对照