本次来分享一下I2C外设,这里以I2C接口的传感器来测试一下。
首先打开STM32CubeMX然后配置I2C1接口参数。
I2C_HandleTypeDef * i2c_table[]=
{
&hi2c1
};
uint8_t I2C_WriteByte(void *i2cbus,uint32_t dev_addr, uint32_t addr,uint8_t Byte)
{
uint32_t status;
status = HAL_I2C_Mem_Write(&hi2c1, dev_addr<<1, addr, I2C_MEMADD_SIZE_8BIT, &Byte, 1, 1000);
return status;
}
uint8_t I2C_ReadByte (void *i2cbus,uint32_t dev_addr, uint32_t addr)
{
uint8_t buff=0;
if(HAL_I2C_Mem_Read(&hi2c1, dev_addr<<1, addr, I2C_MEMADD_SIZE_8BIT, &buff, 1, 1000) == HAL_OK)
return buff;
else return 0;
}
uint8_t I2C_PageWrite(void *i2cbus,uint32_t dev_addr, uint32_t addr,uint8_t *str,uint32_t num)
{
uint32_t status;
if((num == 0)||(str==NULL)) return 1;
status = HAL_I2C_Mem_Write(&hi2c1, dev_addr<<1, addr, I2C_MEMADD_SIZE_8BIT, str, num, 1000);
return status;
}
uint8_t I2C_PageRead (void *i2cbus,uint32_t dev_addr, uint32_t addr,uint8_t *str,uint32_t num)
{
uint32_t status;
if((num == 0)||(str==NULL)) return 1;
status = HAL_I2C_Mem_Read(&hi2c1, dev_addr<<1, addr, I2C_MEMADD_SIZE_8BIT, str, num, 1000);
return status;
}
uint8_t I2C_Write(void *i2cbus,uint32_t dev_addr, uint8_t *cmd,uint32_t len,uint8_t *str,uint32_t num)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t memaddr;
if(len == 1)
{
memaddr = cmd[0];
status = HAL_I2C_Mem_Write(&hi2c1, dev_addr<<1, memaddr, I2C_MEMADD_SIZE_8BIT, str, num, 1000);
}else if(len == 2)
{
memaddr = ((uint32_t)cmd[0]<<8)|cmd[1];
status = HAL_I2C_Mem_Write(&hi2c1, dev_addr<<1, memaddr, I2C_MEMADD_SIZE_16BIT, str, num, 1000);
}
return status;
}
uint8_t I2C_Read(void *i2cbus,uint32_t dev_addr, uint8_t *cmd,uint32_t len,uint8_t *str,uint32_t num)
{
HAL_StatusTypeDef status = HAL_OK;
uint32_t memaddr;
if(len == 1)
{
memaddr = cmd[0];
status = HAL_I2C_Mem_Read(&hi2c1, dev_addr<<1, memaddr, I2C_MEMADD_SIZE_8BIT, str, num, 1000);
}else if(len == 2)
{
memaddr = ((uint32_t)cmd[0]<<8)|cmd[1];
status = HAL_I2C_Mem_Read(&hi2c1, dev_addr<<1, memaddr, I2C_MEMADD_SIZE_16BIT, str, num, 1000);
}
return status;
}
uint8_t I2C_WriteOnly(void *i2cbus,uint32_t dev_addr,uint8_t *str,uint32_t num)
{
if((num == 0)||(str==NULL)) return 1;
HAL_I2C_Master_Transmit(&hi2c1, dev_addr<<1, str, num, 1000);
return 0;
}
uint8_t I2C_ReadOnly(void *i2cbus,uint32_t dev_addr,uint8_t *str,uint32_t num)
{
if((num == 0)||(str==NULL)) return 1;
HAL_I2C_Master_Receive(&hi2c1, dev_addr<<1, str, num, 1000);
return 0;
}
uint8_t I2C_IsDeviceReady(void *i2cbus,uint32_t dev_addr)
{
return HAL_I2C_IsDeviceReady(i2cbus,dev_addr<<1,5000,1000);
}
void * I2C_FindDevice(char *name)
{
return NULL;
}
添加shell控制I2C代码:
#if UART_SHELL == 1 //letter shell
#include "stdlib.h"
#include "string.h"
#include "shell_port.h"
uint8_t is_hex(uint8_t ch)
{
if((ch>='0') && (ch <='9')) return ch-'0';
else if((ch>='A') && (ch <='F')) return (ch-'A'+10);
else if((ch>='a') && (ch <='f')) return (ch-'a'+10);
return 0xff;
}
uint32_t str2hex(char *str)
{
uint32_t n = 0,i = 0;
uint8_t c;
while(*str != '\0')
{
c = is_hex(*str++);
if(c!=0xff)
{
n = (n<<4) + c;
i++;
}
if(i == 8) break;
}
return n;
}
void I2C_AddrDetect(char argc, char **argv)
{
int i,j;
int i2c_bus, dev_addr;
i2c_bus = 0;
dev_addr = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", argv[i]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(argv[i]); //
}else if(!strcmp("dev", argv[i]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(argv[i]); //
}else
{
printf("usage:\r\ni2cdetect [i2cbus [num]] [dev [num]]]\r\n");
return;
}
}
printf("Detect I2C Devive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
for(i=0;i<8;i++)
{
for(j=0;j<16;j++)
{
if(I2C_IsDeviceReady(i2c_table[i2c_bus],(j + i*16)) == HAL_OK) printf("%02X ",j + i*16);
else printf("-- ");
delay_ms(1);
}
printf("\r\n");
}
printf("\r\nDetect I2C addr over.\r\n\r\n");
}
//add cmd
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), i2cdetect, I2C_AddrDetect, I2C detect device address);
void I2C_GetRegData(char argc, char **argv)
{
int i;
int i2c_bus, dev_addr, reg_addr, reg_data;
i2c_bus = 0;
dev_addr = 0;
reg_addr = 0;
reg_data = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", argv[i]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(argv[i]); //
}else if(!strcmp("dev", argv[i]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(argv[i]); //
}else if(!strcmp("reg", argv[i]))
{
i++;
if(i >= argc) break;
reg_addr = str2hex(argv[i]); //
}else
{
printf("usage:\r\ni2cget [i2cbus [num]] [dev [num]] [reg [num]]\r\n");
return;
}
}
printf("I2CDevive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
printf("I2C:GETREG:0x%0X = 0x%0X\r\n\r\n",reg_addr,I2C_ReadByte(i2c_table[i2c_bus],dev_addr,reg_addr));
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), i2cget, I2C_GetRegData, I2C get device reg data);
void I2C_SetRegData(char argc, char **argv)
{
int i;
int i2c_bus, dev_addr, reg_addr, reg_data;
i2c_bus = 0;
dev_addr = 0;
reg_addr = 0;
reg_data = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", argv[i]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(argv[i]); //
}else if(!strcmp("dev",argv[i]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(argv[i]); //
}else if(!strcmp("reg", argv[i]))
{
i++;
if(i >= argc) break;
reg_addr = str2hex(argv[i]); //
}
else if(!strcmp("data", argv[i]))
{
i++;
if(i >= argc) break;
reg_data = str2hex(argv[i]); //
}else
{
printf("usage:\r\ni2cset [i2cbus [num]] [dev [num]] [reg [num]] [data [num]]\r\n");
return;
}
}
printf("I2CDevive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
I2C_WriteByte(i2c_table[i2c_bus],dev_addr,reg_addr,reg_data);
printf("I2C:SETREG:0x%0X = 0x%0X\r\n\r\n",reg_addr,reg_data);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), i2cset, I2C_SetRegData, I2C set device reg data);
#elif UART_SHELL == 2
#include "stdlib.h"
#include "string.h"
#include "nr_micro_shell.h"
uint8_t is_hex(uint8_t ch)
{
if((ch>='0') && (ch <='9')) return ch-'0';
else if((ch>='A') && (ch <='F')) return (ch-'A'+10);
else if((ch>='a') && (ch <='f')) return (ch-'a'+10);
return 0xff;
}
uint32_t str2hex(char *str)
{
uint32_t n = 0,i = 0;
uint8_t c;
while(*str != '\0')
{
c = is_hex(*str++);
if(c!=0xff)
{
n = (n<<4) + c;
i++;
}
if(i == 8) break;
}
return n;
}
void I2C_AddrDetect(char argc, char *argv)
{
int i,j;
int i2c_bus, dev_addr;
i2c_bus = 0;
dev_addr = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(&argv[argv[i]]); //
}else if(!strcmp("dev", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(&argv[argv[i]]); //
}else
{
printf("usage:\r\ni2cdetect [i2cbus [num]] [dev [num]]]\r\n");
return;
}
}
printf("Detect I2C Devive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
for(i=0;i<8;i++)
{
for(j=0;j<16;j++)
{
if(I2C_IsDeviceReady(i2c_table[i2c_bus],(j + i*16)) == HAL_OK) printf("%02X ",j + i*16);
else printf("-- ");
delay_ms(1);
}
printf("\r\n");
}
printf("\r\nDetect I2C addr over.\r\n\r\n");
}
NR_SHELL_CMD_EXPORT(i2cdetect, I2C_AddrDetect, "I2C detect device address");
void I2C_GetRegData(char argc, char *argv)
{
int i;
int i2c_bus, dev_addr, reg_addr, reg_data;
i2c_bus = 0;
dev_addr = 0;
reg_addr = 0;
reg_data = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(&argv[argv[i]]); //
}else if(!strcmp("dev", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(&argv[argv[i]]); //
}else if(!strcmp("reg", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
reg_addr = str2hex(&argv[argv[i]]); //
}else
{
printf("usage:\r\ni2cget [i2cbus [num]] [dev [num]] [reg [num]]\r\n");
return;
}
}
printf("I2CDevive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
printf("I2C:GETREG:0x%0X = 0x%0X\r\n\r\n",reg_addr,I2C_ReadByte(i2c_table[i2c_bus],dev_addr,reg_addr));
}
NR_SHELL_CMD_EXPORT(i2cget, I2C_GetRegData, "I2C get device reg data");
void I2C_SetRegData(char argc, char *argv)
{
int i;
int i2c_bus, dev_addr, reg_addr, reg_data;
i2c_bus = 0;
dev_addr = 0;
reg_addr = 0;
reg_data = 0;
for (i = 1; i < argc; i++)
{
if (!strcmp("i2cbus", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
i2c_bus = atoi(&argv[argv[i]]); //
}else if(!strcmp("dev", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
dev_addr = str2hex(&argv[argv[i]]); //
}else if(!strcmp("reg", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
reg_addr = str2hex(&argv[argv[i]]); //
}
else if(!strcmp("data", &argv[argv[i]]))
{
i++;
if(i >= argc) break;
reg_data = str2hex(&argv[argv[i]]); //
}else
{
printf("usage:\r\ni2cset [i2cbus [num]] [dev [num]] [reg [num]] [data [num]]\r\n");
return;
}
}
printf("I2CDevive:bus=%d,dev=0x%0X\r\n",i2c_bus,dev_addr);
I2C_WriteByte(i2c_table[i2c_bus],dev_addr,reg_addr,reg_data);
printf("I2C:SETREG:0x%0X = 0x%0X\r\n\r\n",reg_addr,reg_data);
}
NR_SHELL_CMD_EXPORT(i2cset, I2C_SetRegData, "I2C Set device reg data");
#endif
下面是硬件连接,板载I2C接口的RPR-0521光照接近传感器和SHTC3温湿度传感器。
#include "drv_rpr0521rs.h"
#define I2C_NUM 0
uint8_t _als_data0_gain,_als_data1_gain;
uint16_t _als_measure_time;
uint8_t RPR0521RS_Init(void)
{
uint8_t temp,index;
uint8_t als_gain_table[] = {1, 2, 64, 128};
uint16_t als_meas_time_table[] = {0,0,0,0,0,100,100,100,100,100,400,400,50,0,0,0};
temp = I2C_ReadByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_MANUFACT_ID);
if(temp != RPR0521RS_MANUFACT_ID_VAL)
{
return 1;
}
temp = I2C_ReadByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_SYSTEM_CONTROL);
if((temp&0x3f) != RPR0521RS_PART_ID_VAL)
{
return 1;
}
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_ALS_PS_CONTROL, RPR0521RS_ALS_PS_CONTROL_VAL);
temp = I2C_ReadByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_PS_CONTROL);
temp |= RPR0521RS_PS_CONTROL_VAL;
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_PS_CONTROL, temp);
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_MODE_CONTROL, RPR0521RS_MODE_CONTROL_VAL);
temp = RPR0521RS_ALS_PS_CONTROL_VAL;
index = (temp >> 4) & 0x03;
_als_data0_gain = als_gain_table[index];
index = (temp >> 2) & 0x03;
_als_data1_gain = als_gain_table[index];
index = RPR0521RS_MODE_CONTROL_VAL & 0x0F;
_als_measure_time = als_meas_time_table[index];
return 0;
}
void RPR0521RS_get_rawdata(uint8_t *buff)
{
I2C_PageRead(I2C_NUM, RPR0521RS_DEVICE_ADDRESS,
RPR0521RS_PS_DATA_LSB,
buff, 6);
}
float RPR0521RS_convert_lx(unsigned short *f)
{
float lx;
float d0, d1, d1_d0;
if (_als_data0_gain == 0) {
return (-1);
}
if (_als_data1_gain == 0) {
return (-1);
}
if (_als_measure_time == 0)
{
return (-1);
} else if (_als_measure_time == 50)
{
if ((f[0] & 0x8000) == 0x8000)
{
f[0] = 0x7FFF;
}
if ((f[1] & 0x8000) == 0x8000)
{
f[1] = 0x7FFF;
}
}
d0 = (float)f[0] * (100 / _als_measure_time) / _als_data0_gain;
d1 = (float)f[1] * (100 / _als_measure_time) / _als_data1_gain;
if (d0 == 0) {
lx = 0;
return (lx);
}
d1_d0 = d1 / d0;
if (d1_d0 < 0.595) {
lx = (1.682 * d0 - 1.877 * d1);
} else if (d1_d0 < 1.015) {
lx = (0.644 * d0 - 0.132 * d1);
} else if (d1_d0 < 1.352) {
lx = (0.756 * d0 - 0.243 * d1);
} else if (d1_d0 < 3.053) {
lx = (0.766 * d0 - 0.25 * d1);
} else {
lx = 0;
}
return (lx);
}
void RPR0521RS_get_psalsval(unsigned int *ps, float *als)
{
unsigned char val[6];
unsigned short rawps;
unsigned short rawals[2];
RPR0521RS_get_rawdata(val);
rawps = ((unsigned short)val[1] << 8) | val[0];
rawals[0] = ((unsigned short)val[3] << 8) | val[2];
rawals[1] = ((unsigned short)val[5] << 8) | val[4];
*ps = rawps;
*als = RPR0521RS_convert_lx(rawals);
}
uint8_t RPR0521RS_read_int(void)
{
return I2C_ReadByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_INTERRUPT_CONTROL);
}
void RPR0521RS_write_int(uint8_t intvalue)
{
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_INTERRUPT_CONTROL,intvalue);
}
void RPR0521RS_Set_PS_threshold(uint16_t ps_high,uint16_t ps_low)
{
uint8_t buff[4];
buff[0] = ps_high&0xff;
buff[1] = (ps_high>>8)&0x0f;
buff[2] = ps_low&0xff;
buff[3] = (ps_low>>8)&0x0f;
I2C_PageWrite(I2C_NUM, RPR0521RS_DEVICE_ADDRESS,
RPR0521RS_PS_TH_LSB,
buff, 4);
}
void RPR0521RS_Set_ALS_threshold(uint16_t als_high,uint16_t als_low)
{
uint8_t buff[4];
buff[0] = als_high&0xff;
buff[1] = (als_high>>8)&0xff;
buff[2] = als_low&0xff;
buff[3] = (als_low>>8)&0xff;
I2C_PageWrite(I2C_NUM, RPR0521RS_DEVICE_ADDRESS,
RPR0521RS_PS_TH_LSB,
buff, 4);
}
void RPR0521RS_power_down(void)
{
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_SYSTEM_CONTROL,0x80);
I2C_WriteByte(I2C_NUM, RPR0521RS_DEVICE_ADDRESS, RPR0521RS_MODE_CONTROL,0);
}
///////////////////////////////////////////////////////////////////////////////
#if UART_SHELL == 1
#include "shell_port.h"
void rpr0521rs_read(char argc, char **argv)
{
unsigned int ps;
float als;
printf("rpr0521rs:%d\r\n",RPR0521RS_Init());
RPR0521RS_get_psalsval(&ps, &als);
printf("ps=%u,\t als=%f.\r\n",ps,als);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), rpr0521, rpr0521rs_read, get light senser rpr0521rs data);
#elif UART_SHELL == 2
#include "nr_micro_shell.h"
void rpr0521rs_read(char argc, char *argv)
{
unsigned int ps;
float als;
printf("rpr0521rs:%d\r\n",RPR0521RS_Init());
RPR0521RS_get_psalsval(&ps, &als);
printf("ps=%u,\t als=%f.\r\n",ps,als);
}
NR_SHELL_CMD_EXPORT(rpr0521, rpr0521rs_read, "get light senser rpr0521rs data");
#endif
#include "drv_shtc3.h"
#define I2C_NUM (&hi2c1)
void shtc3_gpio_init(void)
{
}
void SHTC3_WriteCmd(uint16_t cmd)
{
uint8_t cbuf[2];
cbuf[0]=cmd>>8;
cbuf[1]=cmd&0xff;
I2C_Write(I2C_NUM,SHTC3_ADDRESS,cbuf,2,cbuf,0);
}
void SHTC3_ReadData(uint16_t cmd,uint8_t *buff,uint32_t len)
{
uint8_t cbuf[2];
cbuf[0]=cmd>>8;
cbuf[1]=cmd&0xff;
I2C_Read(I2C_NUM,SHTC3_ADDRESS,cbuf,2,buff,len);
}
int SHTC3_CalcTemperature(uint16_t rawValue)
{
// calculate temperature
// T = -45 + 175 * rawValue / 2^16
return (((175*1 * rawValue)>>16) - 45*1); //放大100倍
}
int SHTC3_CalcHumidity(uint16_t rawValue)
{
// calculate relative humidity
// RH = rawValue / 2^16 * 100
return ((100 * 1 * rawValue)>>16); //放大100倍
}
static uint8_t SHTC3_CheckCRC(uint8_t *buff, uint32_t nbyte)
{
uint32_t i; // byte counter
uint8_t bit; // bit mask
uint8_t crc = 0xFF; // calculated checksum
// calculates 8-Bit checksum with given polynomial
for(i = 0; i < nbyte; i++)
{
crc ^= (buff[i]);
for(bit = 8; bit > 0; --bit)
{
if(crc & 0x80) {
crc = (crc << 1) ^ SHTC3_CRC_POLYNOMIAL;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
uint16_t shtc3_id;
uint32_t SHTC3_Init(void)
{
uint8_t buff[4];
shtc3_id = 0;
shtc3_gpio_init();
SHTC3_ReadData(SHTC3_REG_ID,buff,3);
if(buff[2] != SHTC3_CheckCRC(buff,2))
{
return -1;
}
delay_ms(10);
SHTC3_WriteCmd(SHTC3_REG_WAKEUP);
shtc3_id = (buff[0]<<8)|buff[1];
return shtc3_id;
}
uint8_t SHTC3_GetMode1_TempRH(int *temp, int *humi)
{
uint8_t buff[8];
SHTC3_ReadData(SHTC3_REG_CELPM_TEMP_RH,buff,6);
if((buff[2] != SHTC3_CheckCRC(buff,2))||(buff[5] != SHTC3_CheckCRC(&buff[3],2)))
{
return 1;
}
*temp = SHTC3_CalcTemperature((buff[0]<<8)|buff[1]);
*humi = SHTC3_CalcHumidity((buff[3]<<8)|buff[4]);
return 0;
}
///////////////////////////////////////////////////////////////////////////////
#if UART_SHELL == 1
#include "shell_port.h"
void shtc3_read(char argc, char *argv)
{
int temperature,rh;
printf("SHTC3:%d\r\n",SHTC3_Init());
SHTC3_GetMode1_TempRH(&temperature, &rh);
printf("temperature=%d,\t rh=%d.\r\n",temperature,rh);
}
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0x0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), shtc3, shtc3_read, get temperature senser shtc3 data);
#elif UART_SHELL == 2
#include "nr_micro_shell.h"
void shtc3_read(char argc, char *argv)
{
int temperature,rh;
printf("SHTC3:%d\r\n",SHTC3_Init());
SHTC3_GetMode1_TempRH(&temperature, &rh);
printf("temperature=%d,\t rh=%d.\r\n",temperature,rh);
}
NR_SHELL_CMD_EXPORT(shtc3, shtc3_read, "get temperature senser shtc3 data");
#endif
编译下载之后就可以通过shell命令获取传感器数值了。