Слияние кода завершено, страница обновится автоматически
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h> //open
#include <unistd.h> //read
#include <stdlib.h>
#define u8 unsigned char
#define u16 unsigned short int
#define u32 unsigned int
//gpio 电量采集
#define scl 919
#define sda 916
//这里通过linux 打开文件的方式控制gpio所以比较耗时间
#define I2C_SCL_L set_gpioValue(scl,0)
#define I2C_SCL_H set_gpioValue(scl,1)
#define I2C_SDA_L set_gpioValue(sda,0)
#define I2C_SDA_H set_gpioValue(sda,1)
#define I2C_SCL_OUT set_gpioDirection(scl, "out")
#define I2C_SDA_OUT set_gpioDirection(sda, "out")
#define I2C_SDA_IN set_gpioDirection(sda, "in")
#define I2C_SDA_GET get_gpioValue(sda)
//MCP342 出厂时如果未指定地址则为 1101 000x 最后一位x 如果是写配置则为1 读则为0
#define MCP3421_ADDREAD 0xd1
#define MCP3421_ADDWRITE 0Xd0
//写入配置参数 如0x8c,0x9c; 8:单次转换 9:连续转换;c:18位 3.75 sps ,PGA=1;
//mcp3421初始化不配置 默认为0x90 连续转换 12位,PGA =1
#define MCP3421_OneShot_18BIT_X1 0x8c
#define MCP3421_MoreShot_18BIT_X1 0x9c
//电池 电量显示
#define battery_H 12 //电池的满电电压
#define battery_L 8 //电池的下限电压(需要实际测试)
//create gpio file
void creat_gpio(int n)
{
FILE * fp =fopen("/sys/class/gpio/export","w");
if (fp == NULL)
perror("export open filed");
else
fprintf(fp,"%d",n);
fclose(fp);
}
//设置gpio的方向 "in" or "out"
void set_gpioDirection(int n,char *direction)
{
char path[100] = {0};
sprintf(path,"/sys/class/gpio/gpio%d/direction",n);
FILE * fp =fopen(path,"w");
if (fp == NULL)
perror("direction open filed");
else
fprintf(fp,"%s",direction);
fclose(fp);
}
//设置gpio的电平
void set_gpioValue(int n, int value)
{
char path[64];
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", n);
FILE *fp = fopen(path, "w");
if (fp == NULL)
perror("direction open filed");
else
fprintf(fp, "%d", value);
fclose(fp);
}
//获取gpio的值
int get_gpioValue(int n)
{
char path[64];
char value_str[3];
int fd;
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", n);
fd = open(path, O_RDONLY);
if (fd < 0) {
perror("Failed to open gpio value for reading!");
return -1;
}
if (read(fd, value_str, 3) < 0) {
perror("Failed to read value!");
return -1;
}
close(fd);
return (atoi(value_str));
}
// IIC传输延时函数
void I2C_Delay(int t)
{
int i, j;
for(i=0; i<t; i++)
{
for(j=0; j<12; j++)
{}
}
}
//初始化scl和sda为高电平
void I2C_Init(void)
{
creat_gpio(scl);
creat_gpio(sda);
set_gpioDirection(scl, "out"); //开发板调为输出模式默认为低电平
set_gpioDirection(sda, "out");
set_gpioValue(scl,1);
set_gpioValue(sda,1);
usleep(100); //保持高电平稳定
}
/*******************************************************************************
* 函数名 : I2cStart()
* 函数功能 : 起始信号:在SCL时钟信号在高电平期间SDA信号产生一个下降沿
* 输入 : 无
* 输出 : 无
* 备注 : 起始之后SDA和SCL都为0
*******************************************************************************/
void I2C_Start()
{
I2C_SDA_OUT; //设置输出模式(会将sda拉低)
I2C_Delay(1);
I2C_SDA_H;
I2C_SCL_H;
I2C_SDA_L;
I2C_SCL_L;
I2C_Delay(1);
}
/*******************************************************************************
* 函数名 : I2cStop()
* 函数功能 : 终止信号:在SCL时钟信号高电平期间SDA信号产生一个上升沿
* 输入 : 无
* 输出 : 无
* 备注 : 结束之后保持SDA和SCL都为1;表示总线空闲
*******************************************************************************/
void I2C_Stop()
{
I2C_SDA_OUT; //设置输出模式(会将sda拉低)
I2C_Delay(1);
I2C_SDA_L;
I2C_SCL_H;
I2C_SDA_H;
I2C_Delay(1);
}
/*******************************************************************************
* 函数名 : IIC_Wait_Ack()
* 函数功能 : 检查应答信号:在第9个时钟信号为高电平期间主机释放sda,从机拉低sda
* 输入 : 从机
* 输出 : 返回 0有应答,返回1 无应答
* 备注 :
*******************************************************************************/
unsigned char I2C_Wait_Ack()
{
unsigned int i = 0;
I2C_SDA_IN; //设置sda为输入模式
I2C_SCL_H;
while(I2C_SDA_GET)//等待应答,也就是等待从设备把SDA拉低
{
i++;
if( i > 200) //如果超过时间没有应答发送失败,或者为非应答,表示接收结束
{
I2C_SCL_L;
I2C_SCL_H;
printf("no ack\r\n"); //没有应答
return 1;
}
}
I2C_SCL_L;
return 0;
}
//应答
void I2C_Ack()
{
I2C_SDA_OUT; //会将sda拉低
I2C_Delay(1);
I2C_SCL_L;
I2C_SDA_L;
I2C_SCL_H;
I2C_Delay(1); //从机检测sda的低电平
I2C_SCL_L; //第9个时钟周期结束
}
//非应答
void I2C_NAck()
{
I2C_SDA_OUT; //会将sda拉低
I2C_Delay(1);
I2C_SCL_L;
I2C_SDA_H; //至高sda 表示不应答
I2C_SCL_H;
I2C_Delay(1); //从机检测sda的高电平
I2C_SCL_L; //第9个时钟周期结束
}
/*******************************************************************************
* 函数名 : I2cSendByte(unsigned char dat)
* 函数功能 : 通过I2C发送一个字节。在SCL时钟信号高电平期间,保持发送信号SDA保持稳定
* 输入 : num
* 输出 : 0或1。发送成功返回1,发送失败返回0
* 备注 : 发送完一个字节SCL=0,SDA=1
*******************************************************************************/
unsigned char I2C_SendByte(unsigned char dat)
{
I2C_SDA_OUT; //会将sda拉低
I2C_Delay(1);
unsigned char a=0,b=0;
for(a=0;a<8;a++)//要发送8位,从最高位开始
{
I2C_SCL_L;
if (dat&0x80)
{
I2C_SDA_H;
}
else
{
I2C_SDA_L;
}
dat<<=1;
I2C_SCL_H;
}
I2C_SCL_L;
}
/*******************************************************************************
* 函数名 : I2cReadByte()
* 函数功能 : 使用I2c读取一个字节
* 输入 : 无
* 输出 : dat
* 备注 : 接收完一个字节SCL=0,SDA=1.
*******************************************************************************/
unsigned char I2C_ReadByte()
{
I2C_SDA_IN;
unsigned char a=0,dat=0;
for(a=0;a<8;a++)//接收8个字节
{
dat<<=1;
I2C_SCL_L;
I2C_SCL_H;
if( I2C_SDA_GET )
{
dat |= 0x01;
}
else
{
dat &= 0xfe;
}
I2C_SCL_L;
}
return dat;
}
//MCP3421写配置
void Write_MCP3421(unsigned char WR_Data)
{
I2C_Start();
//写入地址 及 最后位为0,是写操作配置 最后位为1,是读操作配置
I2C_SendByte(0xd0); // 1101 a2 a1 a0 0 发送给第一个字节数据 MCP3421地址字节+R/W命令
// 1101 0000 0xd0 写模式
I2C_Wait_Ack();
I2C_SendByte(WR_Data); //RDY O/C C1 C0 S1 S0 G1 G0
I2C_Wait_Ack();
I2C_Stop();
}
//MCP3421读数据
float READ_MCP3421()
{
unsigned long int elech;
unsigned long int elecm;
unsigned long int elecl;
unsigned long int config;
unsigned long int AD_B_Result;
float AD_F_Result=0.0;
float LSB;
int PGA;
I2C_Start();
I2C_SendByte(0xd1); //0xd1=0b11010001, 最后一位1表示单片机接收数据
I2C_Wait_Ack(); //MCP3421发出应答ACK信号
//读取第二个字节数据 Upper Data Byte
elech=(long int)I2C_ReadByte(); //NULL NULL NULL NULL NULL NULL D17 D16
I2C_Ack(); //主器件发出应答信号
//读取第三个字节数据 Lower Data Byte
elecm=(long int)I2C_ReadByte(); //D15 D14 D13 D12 D11 D10 D9 D8
I2C_Ack(); ////主器件发出应答信号
elecl=(long int)I2C_ReadByte(); //D7 D6 D5 D4 D3 D2 D1 D0
I2C_Ack();
config = (long int)(I2C_ReadByte()); //RDY C1 C0 O/C S1 S0 G1 G0
I2C_NAck();// 停止接收
I2C_Stop();
//开始进行数据转化
AD_B_Result=(elech<<16)|(elecm<<8)|(elecl); //将三个数据进行整合,整合成一个24位的数据
AD_B_Result=AD_B_Result&0x01ffffff; //由于数据elech的前6个字节没有用,所以将其清零
LSB = (float)(2.0 * 2.048) / 262144; //公式 (2*Vref(2.048))/2^n n为分辨率 12,14,16,18
//18为计算为15.625uv
PGA = 1; //增益为1
AD_F_Result = (float)(LSB * AD_B_Result)/PGA; //输出范围 -2.048v-0v-2.048v
return AD_F_Result;
}
float get_adc()
{
int i = 0;
float sum = 0.0;
float data = 0.0;
//为了稳定获取10次求平均数
for(i=0; i<10; i++)
{
sum += READ_MCP3421();
}
//转化为实际电压
data = (sum / 10) /0.163; //0.163为实际输入1v时的测量值
return data;
}
int main()
{
float data = 0;
int show = 0; //剩余电量百分比
I2C_Init();
//写入配置参数 如0x8c,0x9c; 8:单次转换 9:连续转换;c:18位 3.75 sps ,PGA=1;
Write_MCP3421(0X9C);
while(1)
{
//获取到的电压值
data = get_adc();
printf("data=%.3fv\r\n", data);
show = (int)(((data-battery_L)*100)/(battery_H - battery_L));
printf("battery = %d%%\r\n", show);
sleep(2);
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )