中级会员
- 积分
- 254
- 金钱
- 254
- 注册时间
- 2020-3-22
- 在线时间
- 35 小时
|
/********************************************/
时间 :2020/03/24/
作者 :YOKI
导师 :正点原子 左忠凯
硬件 :正点原子 ALPHA I.MX LINUX 开发板
/*******************************************/
本例程通过编写 led、蜂鸣器 按键 练习 GPIO 口的 通用设置
预期功能:通过一个简单的函数实现对任意一个GPIO引脚的读写
GPIOx->GDIR &= ~(1<<0); //GDIR 置 0 输入模式
GPIOx->GDIR |= (1<<0); //GDIR 置 1 输出模式
((GPIOx->DR) >> pin) & 0x01; //读引脚电平
(GPIOx->DR) &= ~(1<<pin);break; //给引脚写 0 低电平
(GPIOx->DR) |= (1<<pin);break; //给引脚写 1 高电平
以上就是这些函数实现的基础
/***************** GPIO口初始化函数 ************************/
/* 参数1:GPIOx GPIO口名称 如:GPIO1、GPIO5
/* 参数2:pin 引脚号 如: 18 、1
/* 参数3:direction 输入输出 如: INPUT output
/* 例如:设置GPIO5_IO01为输出模式:
/* GPIOx_init(GPIO5,1,output);
/*********************************************************/
void GPIOx_init (GPIO_Type *GPIOx, uint8_t pin, uint8_t direction)
{
if (direction == INPUT||direction == input ){
GPIOx->GDIR &= ~(1<<pin); //置0 输入模式
}
if (direction == OUTPUT||direction == output){
GPIOx->GDIR |= (1<<pin); //置1 输出模式
}
}
这是我自己编写的初始化函数,和视频中基本一样,只有函数的最后一个参数稍有不同,我没使用枚举类型的结构体,
而是在 bsp_gpio.h 头文件 中用宏定义 定义代替了:
#define INPUT 0
#define input 0
#define OUTPUT 1
#define output 1
这样更直观一点,当然我还是很赞同视频中的写法,不过大家不必完全照抄 左萌主 的代码,重点是有自己的收获就好,
有自己的想法就去试验以下,哪怕错了也没关系。
/***************** GPIOx引脚写数据**************************/
/* 参数1:GPIOx GPIO口名称 如:GPIO1、GPIO5
/* 参数2:pin 引脚号 如: 18 、1
/* 例如:写GPIO1_IO18 高电平:
/* GPIOx_pin_write(GPIO1,18,1);
*********************************************************/
void GPIOx_pin_write(GPIO_Type *GPIOx, uint8_t pin,int value)
{
// GPIOx->GDIR |= (1<<pin); //置1 输出模式
switch (value)
{
case 0GPIOx->DR) &= ~(1<<pin);break; // 写 0 低电平
case 1GPIOx->DR) |= (1<<pin);break; // 写 1 高电平
defaultGPIOx->DR) &= ~(1<<pin);break; // 默认 写0 低电平
}
}
这个函数只是写数据没用 if 语句换成了 switch 语句 本质上没啥区别,
只是自己觉得这里用 条件分支 switch 更合适更美观。
然后被注释掉的那一条语句留着以后用(想把 void GPIOx_init()函数精简掉)
// GPIOx->GDIR |= (1<<pin); //置1 输出模式
/***************** GPIOx引脚读取函数 ***********************/
/* 参数1:GPIOx GPIO口名称 如:GPIO1、GPIO5
/* 参数2:pin 引脚号 如: 18 、1
/* 例如:读取GPIO1_IO18电平:
/* GPIOx_pin_read(GPIO1,18);
*********************************************************/
int GPIOx_pin_read(GPIO_Type *GPIOx, uint8_t pin)
{
// GPIOx->GDIR &= ~(1<<pin); //置0 输入模式
uint8_t pin_value;
pin_value = ((GPIOx->DR) >> pin) & 0x01;
return( pin_value);
}
这个函数和视频里也一样,我一开始用的 pin_value = ((GPIOx->DR) >> pin); 没用 “按 位 与0” 消除 高位的影响,
验证时发现 返回值不是预期的 0X0 或 0X1 这里备注一下。
解答上一篇《正点原子 linux 第二期 裸机开发视频 P23-24 第13讲 按键输入实验》的疑问:
函数 IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0) 的第四个参数:
0x020E0318 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B 也就是 电气配置寄存器 地址
这里已经把 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B 写上去了
但是却在最后一个(第五个)参数写了0 未对 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B 进行配置
假如直接写成下面这个语句:
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0X1F080);
是否就完成了 IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B 也就是 电气配置寄存器 的配置?
也就不需要后面第二条语句来配置电气属性了
IOMUXC_SetPinConfig(IOMUXC_UART1_CTS_B_GPIO1_IO18,0x1F080);
经过实际验证后发现可以直接在 IO复用时 就对 电气属性进行配置:
IOMUXC_SetPinMux(IOMUXC_UART1_CTS_B_GPIO1_IO18,0X1F080);
效果是完全一样的,不过这只是对GPIO来说是这样,其它功能复用时可不可以这样做以后再验证。
本节思考:
这篇编写的GPIO通用驱动虽然可以对任意的GPIO引脚进行读写,但是前提是这些引脚已经被复用为GPIO,且电气属性配置完成了。
也就是说 GPIO初始化、GPIO读写函数 要在下列两个函数之后使用:
IOMUXC_SetPinMux(); //功能复用
IOMUXC_SetPinConfig(); //电气配置
我的 main.c 中没有直接这两个函数是因为 在 key led beep 初始化时已经进行过一次复用和配置了。
大家试验一下把 前面的初始化注释掉后,直接使用GPIO读写来操作 led beep 和key 看看这几个 GPIO驱动还有没有效果。
/**********************************************************************************************/
个人总结: 通用GPIO编写实验
之前都是一边看视频一边跟着写代码,这一次尝试了先看完视频然后独立写自己的代码实现同样的功能,这样自己的思考会多一点点,
学习是一个模仿加思考的过程,只要原理相同,自己也可以写出好的代码。齐白石说:学我者生,像我死者。大概就是这个意思,
哪怕有时候错了也没关系,慢慢去完善,修改。
以上注释和代码都是在学习 《正点原子 linux 第二期 裸机开发视频 P25 第13.3讲 通用GPIO驱动编写》 过程中
跟着 左萌主 学习并加入了一点点自己的思考写成的,作为一个小菜鸡,我大着胆子发出来跟大家一起记录学习
如果有帮助请大家自行参考、下载,如果 转载 请注明出处,并在论坛和我联系。如果有错误请大神指正!左萌主赛高!
作者 :YOKI
导师 :正点原子 左忠凯 (请允许我叫你一声导师吧)
硬件 :正点原子 ALPHA I.MX LINUX 开发板
/*********************************************************************************************/
|
|