探索WiringPi 模式1下驱动的实现过程
来源:互联网 发布:360软件源 编辑:程序博客网 时间:2024/05/13 20:27
从最简单的gpio实例来分析wiringpi控制io的流程
库的使用有三种方式
int wiringPiSetup (void) ; //使用IO映射,可以更方便的管理IO 需要root权限
int wiringPiSetupGpio (void) ; //不用映射直接用物理IO编号 需要root权限
int wiringPiSetupSys (void) ; //不需要root权限可用脚本直接控制IO)
if (wiringPiSetup () == -1) //初始化库采用IO映射的方式
这里讨论的是采用IO映射的方式
下面是官方给的实例example 下test1.c
/* * test1.c: *一个简单的GPIO实例,来测试wiringpi的函数 */#include <wiringPi.h>#include <stdio.h>#include <stdlib.h>#include <stdint.h>// Simple sequencer data//Triplets of LED, On/Off and delayuint8_t data [] ={ 0, 1, 1, 1, 1, 1, 0, 0, 0, 2, 1, 1, 1, 0, 0, 3, 1, 1, 2, 0, 0, 4, 1, 1, 3, 0, 0, 5, 1, 1, 4, 0, 0, 6, 1, 1, 5, 0, 0, 7, 1, 1, 6, 0, 1, 7, 0, 1, 0, 0, 1,// Extra delay// Back again 7, 1, 1, 6, 1, 1, 7, 0, 0, 5, 1, 1, 6, 0, 0, 4, 1, 1, 5, 0, 0, 3, 1, 1, 4, 0, 0, 2, 1, 1, 3, 0, 0, 1, 1, 1, 2, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1,// Extra delay 9, 9, 9,// End marker} ;int main (void){ int pin ; int dataPtr ; int l, s, d ; printf ("Raspberry Pi wiringPi test program\n") ; if (wiringPiSetup () == -1) //初始化库采用IO映射的方式 exit (1) ; for (pin = 0 ; pin < 8 ; ++pin) pinMode (pin, OUTPUT) ; //将0-7 8个IO设为输出 pinMode (8, INPUT) ; // 引脚 8设为输入检测按键 SDA0 - Has on-board 2k2 pull-up resistor dataPtr = 0 ; for (;;) { l = data [dataPtr++] ;// LED s = data [dataPtr++] ;// State d = data [dataPtr++] ;// Duration (10ths) if ((l + s + d) == 27) { dataPtr = 0 ; continue ; } digitalWrite (l, s) ; //循环控制IO输出 if (digitalRead (8) == 0)// 如果这个引脚GPIO8接地 delay (d * 10) ;// Faster!延时变短加速输出 else delay (d * 100) ; } return 0 ;}
1,初始化库(有三种方式)
int wiringPiSetup (void) ; //使用IO映射,可以更方便的管理IO 需要root权限
int wiringPiSetupGpio (void) ; //不用映射直接用物理IO编号 需要root权限
int wiringPiSetupSys (void) ; //不需要root权限)
if (wiringPiSetup () == -1) //初始化库采用IO映射的方式
具体的初始化步骤
进入函数后
1,首先检查用户权限:因为这个函数必须用超级用户权限 getuid() 调用进程的实际用户ID geteuid() 调用进程的有效用户ID
if (geteuid () != 0)
{
fprintf (stderr, "wiringPi:\n Must be root to call wiringPiSetup().\n (Did you forget sudo?)\n") ;
exit (EXIT_FAILURE) ;
}
2,然后判断是否进入调试模式
if (getenv ("WIRINGPI_DEBUG") != NULL)
{
printf ("wiringPi: Debug mode enabled\n") ;
wiringPiDebug = TRUE ;
}
3,将函数指针和对应的函数连接起来
pinMode = pinModeWPi ;
pullUpDnControl = pullUpDnControlWPi ;
digitalWrite = digitalWriteWPi ;
digitalWriteByte = digitalWriteByteGpio ; // Same code
pwmWrite = pwmWriteWPi ;
setPadDrive = setPadDriveWPi ;
digitalRead = digitalReadWPi ;
waitForInterrupt = waitForInterruptWPi ;
delayMicroseconds = delayMicrosecondsWPi ;
pwmSetMode = pwmSetModeWPi ;
pwmSetRange = pwmSetRangeWPi ;
pwmSetClock = pwmSetClockWPi ;
举个例子
<a>声明函数指针:void (*pinMode) (int pin, int mode) ;
<b>定义一个函数void pinModeWPi (int pin, int mode)
{
pinModeGpio (pinToGpio [pin & 63], mode) ;
}
<c>将函数指针和函数连接起来
pinMode = pinModeWPi ;
<d>使用函数
pinMode (8, INPUT) ; // 引脚 8设为输入检测按键
4,读取树莓派版本信息V1 V2并映射IO口(把IO口顺序整理下方便使用)
boardRev = piBoardRev () ;
if (boardRev == 1)
pinToGpio = pinToGpioR1 ;
else
pinToGpio = pinToGpioR2 ;
5,接下来就是申请和分配内存,初始化时钟
2,配置IO功能
pinMode (pin, OUTPUT) ; //将0-7 8个IO设为输出
pinMode (8, INPUT) ; // 引脚 8设为输入检测按键
由上面的指针函数注册流程可以看出来
pinMode (8, INPUT) ;真实的调用过程是
pinMode (8, INPUT)-----pinModeWPi (int pin, int mode)----pinModeGpio (pinToGpio [pin & 63], mode) ;
所以我们要关注pinModeGpio (pinToGpio [pin & 63], mode) 的实现,这里已经开始操作ARM的寄存器了(63=0011 1111)
定义一个寄存器的过程
(补充下基础知识 在一个数值前加*就相当于取这个地址里面的数值 uchar p=200; value=*p)
#define BCM2708_PERI_BASE 0x20000000 //寄存器在ARM中的起始地址
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) //GPIO_BASE寄存器起始地址
static volatile uint32_t *gpio ; //定义一个值随时可能变化的指针gpio指向那个需要操作的寄存器
//用户空间映射
gpio = (uint32_t *)mmap((caddr_t)gpioMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_BASE) ;
gpio指向了GPIO_BASE 这样就可以直接操作*gpio就等于修改了GPIO_BASE寄存器的值
最终的使用
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // Sets bits to zero = input
pinModeGpio (pinToGpio [pin & 63], mode) ;函数内容
// register int barrier ;
int fSel, shift, alt ;
pin &= 63 ;
fSel = gpioToGPFSEL [pin] ; //计算GPIO位偏移量
shift = gpioToShift [pin] ; //设置某一位的偏移量
/**/ if (mode == INPUT)
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) ; // 将输入输出控制位置0=做输入用
else if (mode == OUTPUT)
*(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | (1 << shift) ; //置1做输出
else if (mode == PWM_OUTPUT)
{
if ((alt = gpioToPwmALT [pin]) == 0) // Not a PWM pin
return ;
3,IO数据输入/输出
digitalWrite (l, s) ; //循环控制IO输出
if (digitalRead (8) == 0) // 如果这个引脚GPIO8接地
数字IO口的读写函数实现流程和上面的流程大致是一样的只不过操作了不同的寄存器而已
digitalWrite (l, s) //控制输出
if (digitalRead (8) == 0) //检测输入
函数先是声明一个函数指针
实现一个函数
然后让指针指向这个函数
digitalWrite = digitalWriteWPi ;
void digitalWriteWPi (int pin, int value)
{
pin = pinToGpio [pin & 63] ;
if (value == LOW)
*(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ;
else
*(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ;
}
- 探索WiringPi 模式1下驱动的实现过程
- [树莓派2]--wiringPi驱动5110
- 【探索】VS下虚继承实现的方法-1
- 在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之二 引入wiringPi库
- 探索图片填充模式二--CenterCrop模式的实现
- 在RedHat AS5.0下安装minicom的探索过程
- 在RedHat AS5.0下安装buildroot的探索过程
- wince下wave驱动的调用过程
- nandflash驱动的读写操作实现过程
- Unity3D在WebPlayer模式下的异常上报探索
- Unity3D在WebPlayer模式下的异常上报探索
- c#写驱动的探索
- 树莓派-wiringPi-wiringPi-C的i2c库使用
- 关于AJAX类库实现模式的探索
- 探索ImageView图片填充算法--fitCenter模式的实现
- 探索ImageView图片填充算法–fitCenter模式的实现
- WINCE下RTL8201CL网卡驱动探索
- 树莓派-wiringPI-设置引脚编号模式
- Makefile常用函数总结
- sqlserver删除log文件清空日志
- codeigniter 管理cookie创建cookie修改cookie删除cookie
- java判断是否是乱码
- 喜欢的文言文
- 探索WiringPi 模式1下驱动的实现过程
- 应届生就业准备
- Discuz论坛二级域名设置
- 日期的格式化以及随机生成字符串
- java Object类占用内存大小计算
- java求两个集合的交集和并集
- FlexGrid控件的简单实用
- java Queue 的用法
- java里面有关Session和cookie的一些操作方法