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: 此外在检索中已经有大神封装好了这部分的工作,各位也可以直接调用。