WiringPi是一个用C语言编写的树莓派(RaspberryPi)软件包,可用于树莓派GPIO引脚控制、串口通信、SPI通信及I2C通信等功能,非常适合熟悉C/C++的人员在树莓派上进行软件开发。
WiringPi的作者是Gordon Henderson,其官方网址为http://wiringpi.com。WiringPi遵循GNU GPLv3公约,任何人都可以免费使用该软件包。
1、WiringPi的安装与更新
WiringPi预装(Pre-installed)在标准的树莓派操作系统Raspbin中。可以使用下面的命令进行安装:
sudo apt-get install wiringpi
如果需要更新WiringPi,可以使用系统更新命令:
sudo apt-get update sudo apt-get upgrade
WiringPi安装完成后,可以使用下面的命令测试是否安装成功:
sudo gpio -v
如果系统中安装了WiringPi,该命令可以显示出其版本号、作者及当前树莓派的一些信息;如下图所示:
2、WiringPi的引脚定义
WiringPi对树莓派物理引脚进行了封装,定义了一套自己的引脚编号。
如果要查看当前树莓派的引脚编号,可以使用如下命令:
sudo gpio readall
下面这张图是gpio readall读出的树莓派3B的引脚定义:
树莓派的物理引脚、BCM引脚和WiringPi引脚是三种不同的定义,下面这张图看起来更清晰美观一些:
3、WiringPi的库函数
WiringPi提供了很多函数用于各种功能,包括如下库:
- WiringPi配置函数(WiringPi Setup functions);
- WiringPi核心函数(WiringPi Core functions);
- 树莓派专用函数(Raspberry Pi Specific functions);
- 时间函数(Time functions);
- 程序优先级/中断/线程函数(Process priority/interrupts/thread functions);
- 串口通信库函数(Serial Library functions);
- SPI通信库函数(SPI Library functions);
- I2C通信库函数(IC2 Library functions);
- 移位库函数(Shift Library functions);
- 软件PWM库函数(Software PWM Library functions);
- 软件方波/音频库函数(Software Tone Library functions);
4、 代码编写
树莓派端
#include "stdio.h" #include "wiringPi.h" #include "wiringPiI2C.h" #include "pthread.h" #include "unistd.h" void *pthread_fun(void *arg) { int fd = *((int*)arg); int Tx_buf = 12; while(1) { wiringPiI2CWrite(fd, Tx_buf); sleep(1); } return NULL; } int main(int argc, char *argv[]) { int fd, err; int Rx_buf; pthread_t tid; //对wiringPi初始化 if(wiringPiSetup() != 0) { printf("wiringPi error!\n"); return -1; } //指定i2c从机设备,并初始化i2c fd = wiringPiI2CSetup(0x28); if(fd < 0) { printf("wiringPiI2CSetup error!\n"); return fd; } err = pthread_create(&tid, NULL, pthread_fun, &fd); if(err != 0) { printf("create pthread error\n"); return -2; } while(1) { Rx_buf = 0; //读取数据 Rx_buf = wiringPiI2CRead(fd); //判断是否读取成功 if(Rx_buf != 0) printf("Temperature is %d ℃\n", Rx_buf); sleep(1); } return 0; }
STM32F103硬件i2c代码
/********************************************************************************************************* * 包含头文件 *********************************************************************************************************/ #include "iic.h" /********************************************************************************************************* * 宏定义 *********************************************************************************************************/ /********************************************************************************************************* * 内部变量 *********************************************************************************************************/ u8 IIC1_Rx_Buff = 0; u8 IIC1_Tx_Buff = 67; //#define SIZE2 sizeof(IIC1_Tx_Buff) uint32_t state; /********************************************************************************************************* * 内部函数声明 *********************************************************************************************************/ /********************************************************************************************************* * 内部函数实现 *********************************************************************************************************/ /********************************************************************************************************* * 函数名称: * 函数功能: * 输入参数: * 输出参数: * 返 回 值: * 创建日期: * 注 意: *********************************************************************************************************/ /********************************************************************************************************* * API函数实现 *********************************************************************************************************/ /********************************************************************************************************* * 函数名称: InitI2C1 * 函数功能: 初始化I2C1 * 输入参数: void * 输出参数: void * 返 回 值: void * 创建日期: 2019年4月21日 * 注 意: PB6:SCL; PB7:SDA *********************************************************************************************************/ void InitI2C1(void) { GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; NVIC_InitTypeDef NVIC_InitStruct; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //GPIO配置 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD; //设置为复用开漏输出,实现iic的线与逻辑 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); //I2C1配置 I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; //使能ack I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //7位设备地址 I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//占空比为1/2 I2C_InitStruct.I2C_ClockSpeed = 100000; //时钟频率为100k I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; I2C_InitStruct.I2C_OwnAddress1 = 0x50; //设置硬件从机地址 I2C_Init(I2C1, &I2C_InitStruct); //NVIC配置 NVIC_InitStruct.NVIC_IRQChannel = I2C1_EV_IRQn; //事件中断 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStruct); NVIC_InitStruct.NVIC_IRQChannel = I2C1_ER_IRQn; //错误中断 NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStruct); I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_ERR | I2C_IT_BUF, ENABLE); I2C_Cmd(I2C1, ENABLE); } /********************************************************************************************************* * 函数名称: I2C1_EV_IRQHandler * 函数功能: I2C1事件中断服务函数 * 输入参数: void * 输出参数: void * 返 回 值: void * 创建日期: 2019年4月21日 * 注 意: *********************************************************************************************************/ void I2C1_EV_IRQHandler(void) { //static u8 s_iRdata; //static u8 s_iTdata; state = I2C_GetLastEvent(I2C1); switch(state) { //EV1(receive)(从机匹配地址成功) case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED: I2C_ReadRegister(I2C1, I2C_Register_SR1); //读取SR1 I2C_ReadRegister(I2C1, I2C_Register_SR2); //读取SR2后,硬件自动将SR1->ADDR清零 //s_iRdata = 0; break; //EV2(Byte received) case I2C_EVENT_SLAVE_BYTE_RECEIVED: IIC1_Rx_Buff = I2C_ReceiveData(I2C1);//读取DR寄存器硬件将自动将SR1->RxNE清零 //IIC1_Rx_Buff[s_iRdata] = I2C_ReceiveData(I2C1);//读取DR寄存器硬件将自动将SR1->RxNE清零 //s_iRdata++; break; //EV4(stop) case I2C_EVENT_SLAVE_STOP_DETECTED: I2C_ReadRegister(I2C1, I2C_Register_SR1); //读取SR1 I2C1->CR1 |= 0x0001; //写CR1->PE为1,启动I2C1 break; //EV1(transmitter) case I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED: I2C_ReadRegister(I2C1, I2C_Register_SR1); //读取SR1 I2C_ReadRegister(I2C1, I2C_Register_SR2); //读取SR2后,硬件自动将SR1->ADDR清零 //s_iTdata = 0; break; //EV3、EV3-1(Byte transmit) case I2C_EVENT_SLAVE_BYTE_TRANSMITTING: case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: //I2C_SendData(I2C1, IIC1_Tx_Buff[s_iTdata++]); //写I2C->DR后硬件将自动清除TxE位 I2C_SendData(I2C1, IIC1_Tx_Buff); //写I2C->DR后硬件将自动清除TxE位 break; //EV3-2 case I2C_EVENT_SLAVE_ACK_FAILURE: I2C1->SR1 &= 0xFBFF; //写SR1->AF = 0以清除AF位 break; default: break; } } /********************************************************************************************************* * 函数名称: I2C1_ER_IRQHandler * 函数功能: I2C1错误中断服务函数 * 输入参数: void * 输出参数: void * 返 回 值: void * 创建日期: 2019年4月21日 * 注 意: *********************************************************************************************************/ void I2C1_ER_IRQHandler(void) { if(I2C_GetITStatus(I2C1, I2C_IT_SMBALERT)) { I2C_ClearITPendingBit(I2C1, I2C_IT_SMBALERT); } else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) { I2C_ClearITPendingBit(I2C1, I2C_IT_TIMEOUT); } else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) { I2C_ClearITPendingBit(I2C1, I2C_IT_PECERR); } else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) { I2C_ClearITPendingBit(I2C1, I2C_IT_OVR); } else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) { I2C_ClearITPendingBit(I2C1, I2C_IT_AF); } else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) { I2C_ClearITPendingBit(I2C1, I2C_IT_ARLO); } else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) { I2C_ClearITPendingBit(I2C1, I2C_IT_BERR); } I2C1->CR1 |= 0x0001; //启动I2C1 I2C1->SR1 = 0; I2C1->SR2 = 0; }
编译
gcc i2c_wiringPi.c -o i2c_wiringPi -lpthread -lwiringPi ./i2c_wiringPi
Tip: 此外在检索中已经有大神封装好了这部分的工作,各位也可以直接调用。