本文章基于STM32F1 HAL库文件下进行编写测试的代码,VEML7700传感器采用IIC通信,本实验为大学本科的课程设计,已经测试成功,均可在数码管和OLED上进行显示,效果如下:
在黑暗的环境下的光强(单位 lux):
在手机灯光照射下的光强(单位 lux):
现贴如代码如下:
iic.c
#include <stdio.h>
#include "i2c.h"
#include "update.h"
#include <string.h>
#if I2C1_MODE == I2C1_MODE_POLL
/**
* PB10 PB11 config I2C1
*/
void i2c1_config(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* enable I2C1 clock */
rcu_periph_clock_enable(RCU_I2C1);
/* connect PB10 to I2C1_SCL */
/* connect PB11 to I2C2_SDA */
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);//配置PB10,PB11为复用功能
/* configure I2C clock */
i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
/* configure I2C address */
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C1_SLAVE_ADDR);
/* enable I2C1 */
i2c_enable(I2C1);
/* enable acknowledge */
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
void i2c1_write_data_by_reg(uint8_t slave_addr,uint8_t* p_buffer, uint8_t write_address, uint8_t number_of_byte)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
/* wait until the transmit data buffer is empty */
while( SET != i2c_flag_get(I2C1, I2C_FLAG_TBE));
/* send the EEPROM's internal address to write to : only one byte address */
i2c_data_transmit(I2C1, write_address);
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
/* while there is data to be written */
while(number_of_byte--){
i2c_data_transmit(I2C1, *p_buffer);
/* point to the next byte to be written */
p_buffer++;
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
}
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until the stop condition is finished */
while(I2C_CTL0(I2C1)&0x0200);
}
void i2c1_read_data_by_reg(uint8_t slave_addr,uint8_t* p_buffer, uint8_t read_address, uint16_t number_of_byte)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
if(2 == number_of_byte){
i2c_ackpos_config(I2C1,I2C_ACKPOS_NEXT);
}
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
/* wait until the transmit data buffer is empty */
while(SET != i2c_flag_get( I2C1 , I2C_FLAG_TBE));
/* enable I2C1*/
i2c_enable(I2C1);
/* send the EEPROM's internal address to write to */
i2c_data_transmit(I2C1, read_address);
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_RECEIVER);
if(number_of_byte < 3){
/* disable acknowledge */
i2c_ack_config(I2C1,I2C_ACK_DISABLE);
}
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
if(1 == number_of_byte){
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
}
/* while there is data to be read */
while(number_of_byte){
if(3 == number_of_byte){
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
/* disable acknowledge */
i2c_ack_config(I2C1,I2C_ACK_DISABLE);
}
if(2 == number_of_byte){
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
}
/* wait until the RBNE bit is set and clear it */
if(i2c_flag_get(I2C1, I2C_FLAG_RBNE)){
/* read a byte from the EEPROM */
*p_buffer = i2c_data_receive(I2C1);
/* point to the next location where the byte read will be saved */
p_buffer++;
/* decrement the read bytes counter */
number_of_byte--;
}
}
/* wait until the stop condition is finished */
while(I2C_CTL0(I2C1)&0x0200);
/* enable acknowledge */
i2c_ack_config(I2C1,I2C_ACK_ENABLE);
i2c_ackpos_config(I2C1,I2C_ACKPOS_CURRENT);
}
#elif I2C1_MODE == I2C1_MODE_DMA
uint8_t i2c1_buff_rx[128];
static void i2c1_dma_rx_config(uint8_t *p_data,uint8_t len)
{
dma_parameter_struct dma_init_struct;
/* initialize DMA channel4 */
dma_deinit(DMA0, DMA_CH4);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)p_data;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = len;
dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH4, &dma_init_struct);
}
static void i2c1_dma_tx_config(uint8_t *p_data,uint8_t len)
{
dma_parameter_struct dma_init_struct;
/* initialize DMA channel3 */
dma_deinit(DMA0, DMA_CH3);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)p_data;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = len;
dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C1);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH3, &dma_init_struct);
}
void i2c1_dma_init(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_DMA0);
/* enable I2C1 clock */
rcu_periph_clock_enable(RCU_I2C1);
/* connect PB10 to I2C1_SCL */
/* connect PB11 to I2C2_SDA */
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);//配置PB10,PB11为复用功能
/* configure I2C clock */
i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
/* configure I2C address */
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0xff);
/* enable I2C1 */
i2c_enable(I2C1);
/* enable acknowledge */
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
static void i2c1_dma_tx_data(uint8_t slave_addr,uint8_t *p_data,uint8_t len)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
/* wait until the transmit data buffer is empty */
while( SET != i2c_flag_get(I2C1, I2C_FLAG_TBE));
i2c1_dma_tx_config(p_data,len);
/* enable I2C1 DMA */
i2c_dma_config(I2C1, I2C_DMA_ON);
/* enable DMA0 channel3 */
dma_channel_enable(DMA0, DMA_CH3);
/* DMA0 channel3 full transfer finish flag */
while(!dma_flag_get(DMA0, DMA_CH3, DMA_FLAG_FTF));
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until the stop condition is finished */
while(I2C_CTL0(I2C1)&0x0200);
}
/**
* 封装一个函数按寄存器写的函数,寄存器地址可以有多位。
* 数据可以有多个
* dma方式
*/
void i2c1_dma_send_data(uint8_t slave_addr,uint8_t *reg_addr,
uint16_t addr_len,uint8_t *p_data,uint8_t data_len)
{
uint8_t data[I2C_TX_RX_DATA_LEN_MAX] = {0};
uint8_t *p;
if ((addr_len + data_len) > I2C_TX_RX_DATA_LEN_MAX)
{
perror("data to long and return\r\n");
return ;
}
p = data;
memcpy(p,reg_addr,addr_len);
p += addr_len;
memcpy(p,p_data,data_len);
i2c1_dma_tx_data(slave_addr,data,(addr_len+data_len));
}
void i2c1_dma_receive_data(uint8_t slave_addr, uint8_t *reg_addr,uint16_t addr_len,
uint8_t* p_buffer, uint16_t number_of_byte)
{
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY));
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_TRANSMITTER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
/* wait until the transmit data buffer is empty */
while(SET != i2c_flag_get( I2C1 , I2C_FLAG_TBE));
/* enable I2C1*/
i2c_enable(I2C1);
/* send the EEPROM's internal address to write to */
while (addr_len)
{
i2c_data_transmit(I2C1, *reg_addr++);
addr_len--;
/* wait until BTC bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_BTC));
}
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until SBSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_SBSEND));
/* send slave address to I2C bus */
i2c_master_addressing(I2C1, slave_addr, I2C_RECEIVER);
/* wait until ADDSEND bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_ADDSEND));
/* clear the ADDSEND bit */
i2c_flag_clear(I2C1,I2C_FLAG_ADDSEND);
if(number_of_byte < 2)
{
/* disable acknowledge */
i2c_ack_config(I2C1, I2C_ACK_DISABLE);
/* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register (I2C_STAT0 has already been read) */
i2c_flag_get(I2C1, I2C_FLAG_ADDSEND);
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C1);
/* wait for the byte to be received */
while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE));
/* read the byte received from the EEPROM */
*p_buffer = i2c_data_receive(I2C1);
/* decrement the read bytes counter */
number_of_byte--;
}
else
{
i2c1_dma_rx_config(p_buffer,number_of_byte);
i2c_dma_last_transfer_config(I2C1, I2C_DMALST_ON);
/* enable I2C1 DMA */
i2c_dma_config(I2C1, I2C_DMA_ON);
/* enable DMA0 channel5 */
dma_channel_enable(DMA0, DMA_CH4);
/* wait until BTC bit is set */
while(!dma_flag_get(DMA0, DMA_CH4, DMA_FLAG_FTF));
}
/* wait until the stop condition is finished */
while(I2C_CTL0(I2C1)&0x0200);
i2c_stop_on_bus(I2C1);
/* enable acknowledge */
i2c_ack_config(I2C1,I2C_ACK_ENABLE);
i2c_ackpos_config(I2C1,I2C_ACKPOS_CURRENT);
}
#elif I2C1_MODE == I2C1_MODE_SLAVE
volatile uint8_t i2c_txbuffer[128] = {0};
volatile uint8_t i2c_rxbuffer[128];
volatile uint16_t i2c_rx_num;
volatile uint16_t i2c_tx_num;
static uint8_t isfirst = 0;
void i2c1_slave_config(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* enable I2C1 clock */
rcu_periph_clock_enable(RCU_I2C1);
/* connect PB10 to I2C1_SCL */
/* connect PB11 to I2C2_SDA */
gpio_init(GPIOB, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10 | GPIO_PIN_11);//配置PB10,PB11为复用功能
/* configure I2C clock */
i2c_clock_config(I2C1, I2C1_SPEED, I2C_DTCY_2);
/* configure I2C address */
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C1_OWN_ADDRESS7);
/* enable I2C1 */
i2c_enable(I2C1);
/* enable acknowledge */
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
nvic_irq_enable(I2C1_EV_IRQn, 0, 2);
nvic_irq_enable(I2C1_ER_IRQn, 0, 1);
/* enable the I2C1 interrupt */
i2c_interrupt_enable(I2C1, I2C_INT_ERR);
i2c_interrupt_enable(I2C1, I2C_INT_BUF);
i2c_interrupt_enable(I2C1, I2C_INT_EV);
}
/*!
\brief handle I2C1 event interrupt request
\param[in] none
\param[out] none
\retval none
*/
void I2C1_EventIRQ_Handler(void)
{
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)) {
/* clear the ADDSEND bit */
if (isfirst == 0)
{
isfirst = 1;
i2c_rx_num = 0;
}
else
{
isfirst = 0;
i2c_tx_num = 0;
send_i2c_message(i2c_rxbuffer,i2c_rx_num);
}
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND);
} else if((i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_TBE)) && (!i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR))) {
/* send a data byte */
//printf("now send data %d: \r\n",i2c_tx_num);
i2c_data_transmit(I2C1, i2c_txbuffer[i2c_tx_num++]);
} else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)) {
/* if reception data register is not empty ,I2C1 will read a data from I2C_DATA */
i2c_rxbuffer[i2c_rx_num] = i2c_data_receive(I2C1);
i2c_rx_num++;
} else if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET)) {
//printf("get num == %d\r\n",i2c_rx_num);
handle_i2c_message(i2c_rxbuffer,i2c_rx_num);
/* clear the STPDET bit */
i2c_enable(I2C1);
i2c_rx_num = 0;
i2c_tx_num = 0;
isfirst = 0;
}
}
/*!
\brief handle I2C1 error interrupt request
\param[in] none
\param[out] none
\retval none
*/
void I2C1_ErrorIRQ_Handler(void)
{
/* no acknowledge received */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_AERR)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_AERR);
}
/* SMBus alert */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBALT)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBALT);
}
/* bus timeout in SMBus mode */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_SMBTO)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_SMBTO);
}
/* over-run or under-run when SCL stretch is disabled */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_OUERR)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_OUERR);
}
/* arbitration lost */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_LOSTARB)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_LOSTARB);
}
/* bus error */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_BERR)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_BERR);
}
/* CRC value doesn't match */
if(i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_PECERR)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_PECERR);
}
// /* disable the I2C1 interrupt */
// i2c_interrupt_disable(I2C1, I2C_INT_ERR);
// i2c_interrupt_disable(I2C1, I2C_INT_BUF);
// i2c_interrupt_disable(I2C1, I2C_INT_EV);
}
#elif I2C1_MODE == I2C1_MODE_SW
#include "main.h"
//#define VEML7700_SCL_Pin GPIO_PIN_6
//#define VEML7700_SCL_GPIO_Port GPIOB
//#define VEML7700_SDA_Pin GPIO_PIN_7
//#define VEML7700_SDA_GPIO_Port GPIOB
#define swi2c_sda_high HAL_GPIO_WritePin(VEML7700_SDA_GPIO_Port,VEML7700_SDA_Pin,GPIO_PIN_SET)
#define swi2c_sda_low HAL_GPIO_WritePin(VEML7700_SDA_GPIO_Port,VEML7700_SDA_Pin,GPIO_PIN_RESET)
#define swi2c_sda_read ((VEML7700_SDA_GPIO_Port->IDR & VEML7700_SDA_Pin) != 0) /* 读SDA口线状态 */
#define swi2c_scl_high HAL_GPIO_WritePin(VEML7700_SCL_GPIO_Port,VEML7700_SCL_Pin,GPIO_PIN_SET)
#define swi2c_scl_low HAL_GPIO_WritePin(VEML7700_SCL_GPIO_Port,VEML7700_SCL_Pin,GPIO_PIN_RESET)
void swi2c_config(void)
{ /* enable GPIOB clock */
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = VEML7700_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(VEML7700_SDA_GPIO_Port, &GPIO_InitStruct);
swi2c_sda_high;
swi2c_scl_high;
}
void delay_1us(uint16_t us)
{
HAL_Delay_us(us);
}
/**
* SDA PB11 input mode
*/
static void swi2c_sda_config_input_mode(void)
{
// gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = VEML7700_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(VEML7700_SDA_GPIO_Port, &GPIO_InitStruct);
}
/**
* SDA PB11 output mode
*/
static void swi2c_sda_config_output_mode(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = VEML7700_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(VEML7700_SDA_GPIO_Port, &GPIO_InitStruct);
// gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
}
//开始信号
void swi2c_start(void)
{
swi2c_sda_config_output_mode(); //SDA定义为输出
swi2c_sda_high;
swi2c_scl_high;
delay_1us(4);
swi2c_sda_low;
delay_1us(4);
swi2c_scl_low;
}
void swi2c_stop(void)//停止信号
{
swi2c_sda_config_output_mode(); //SDA定义为输出
swi2c_scl_low;
swi2c_sda_low;
delay_1us(4);
swi2c_scl_high;
delay_1us(4);
swi2c_sda_high; //发送 I2C 总线结束信号
delay_1us(4);
}
uint8_t swi2c_wait_ack(void)//等待应答信号:0-应答;1-非应答
{
uint8_t uc_time = 0;
swi2c_sda_high;
swi2c_sda_config_input_mode(); //SDA定义为输入
delay_1us(4);
swi2c_scl_high;
delay_1us(1);
while (swi2c_sda_read)
{
uc_time++;
if (uc_time > 250)
{
swi2c_stop();
return 1;
}
}
delay_1us(4);
swi2c_scl_low;
return 0;
}
void swi2c_ack(void)//产生 ACK 应答
{
swi2c_scl_low;
swi2c_sda_config_output_mode();
swi2c_sda_low;
delay_1us(2);
swi2c_scl_high;
delay_1us(2);
swi2c_scl_low;
}
void swi2c_no_ack(void)//产生 NACK 非应答
{
swi2c_scl_low;
swi2c_sda_config_output_mode();
swi2c_sda_high;
delay_1us(2);
swi2c_scl_high;
delay_1us(2);
swi2c_scl_low;
}
//IIC 发送一个字节
void swi2c_write_byte(uint8_t txd)
{
uint8_t t;
swi2c_sda_config_output_mode();
swi2c_scl_low; //拉低时钟开始数据传输
for(t = 0;t < 8;t++)
{
if((txd<<t) & 0x80)//表示数据是1
swi2c_sda_high;
else
swi2c_sda_low;
delay_1us(4);
swi2c_scl_high;
delay_1us(4);
swi2c_scl_low;
//delay_us(2);
}
}
//读一个字节
uint8_t swi2c_read_byte(void)
{
uint8_t i,receive = 0;
swi2c_sda_config_input_mode();
for(i = 0;i < 8;i++ )
{
delay_1us(4);
swi2c_scl_high;
receive <<= 1;
if(swi2c_sda_read == 1)
{
receive ++;
}
delay_1us(4);
swi2c_scl_low;
}
return receive;
}
//只写地址
uint8_t write_device_addr(uint8_t addr)
{
uint8_t read_ack = 0;
swi2c_start();
swi2c_write_byte(addr);
read_ack = swi2c_wait_ack();
swi2c_stop();
return(read_ack);
}
//在总线上搜寻挂载的器件地址
void swi2c_search_device_addr(void)
{
uint8_t result = 0;
uint8_t j = 0;
for(j = 0;j < 128; j++)
{
if((j % 16) == 0)
{
printf("\r\n");
}
result = write_device_addr(j << 1);
if(result == 0)
{
printf(" %X ",j << 1);//%X 十六进制输出,大写;%x 小写
}
else
{
printf(" -- ");
}
}
printf("\r\n");
}
//读指定器件的指定位置中的一个字节
uint8_t swi2c_device_read_one_byte(uint8_t device_addr,uint8_t reg_addr)
{
uint8_t dat;
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
swi2c_write_byte(reg_addr);//写位置
swi2c_wait_ack();
swi2c_start();
swi2c_write_byte((device_addr) | 0x01);//读写位改为读
swi2c_wait_ack();
dat = swi2c_read_byte();
swi2c_no_ack();//读一个字节结束
swi2c_stop();
return dat;
}
void swi2c_device_write_one_byte(uint8_t device_addr,uint8_t reg_addr,uint8_t data)//写指定器件的指定位置中的一个字节
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
swi2c_write_byte(reg_addr);//写位置
swi2c_wait_ack();
swi2c_write_byte(data);//写数据
swi2c_wait_ack();
swi2c_stop();
}
//连续读指定器件的指定位置中的多个字节
void swi2c_device_read_bytes(uint8_t device_addr,uint8_t reg_addr,uint8_t *buf,uint8_t len)
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
swi2c_write_byte(reg_addr);//写位置
swi2c_wait_ack();
swi2c_start();
swi2c_write_byte((device_addr) | 0x01);//读写位改为读
swi2c_wait_ack();
while(len > 1)
{
*buf++ = swi2c_read_byte();
swi2c_ack();
len--;
}
*buf = swi2c_read_byte();//循环体结束指针已经指向最后一个字节存放位置
swi2c_no_ack();//读一个字节结束
swi2c_stop();
}
//连续写指定器件的指定位置中的多个字节
void swi2c_device_write_bytes(uint8_t device_addr,uint8_t reg_addr,uint8_t *buf,uint8_t len)
{
while(len > 0)
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
swi2c_write_byte(reg_addr++);//写位置
swi2c_wait_ack();
swi2c_write_byte(*buf++);//写数据
swi2c_wait_ack();
swi2c_stop();//发送完结束信号后,器件才会把数据进行擦写操作,搬运到非易失区,这段时间器件不再响应主机操作
HAL_Delay(10);//eeprom连续写时必须加,否则下个字节写入失败
len--;
}
}
void swi2c_device_write_data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len,uint8_t *buf,uint8_t len)
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
while(reg_len)
{
swi2c_write_byte(*reg_addr++);//写位置
swi2c_wait_ack();
reg_len--;
}
while(len)
{
swi2c_write_byte(*buf++);//写位置
swi2c_wait_ack();
len--;
}
swi2c_stop();
}
void swi2c_write_data(uint8_t device_addr,uint8_t *buf,uint8_t len)
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
while(len)
{
swi2c_write_byte(*buf++);//写位置
swi2c_wait_ack();
len--;
}
swi2c_stop();
}
void swi2c_device_read_data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len,uint8_t *buf,uint8_t len)
{
swi2c_start();
swi2c_write_byte(device_addr);//写地址,7位地址左移,低位补0
swi2c_wait_ack();//等待应答
while (reg_len/* condition */)
{
/* code */
swi2c_write_byte(*reg_addr++);//写位置
swi2c_wait_ack();
reg_len--;
}
swi2c_start();
swi2c_write_byte((device_addr) | 0x01);//读写位改为读
swi2c_wait_ack();
while(len > 1)
{
*buf++ = swi2c_read_byte();
swi2c_ack();
len--;
}
*buf = swi2c_read_byte();//循环体结束指针已经指向最后一个字节存放位置
swi2c_no_ack();//读一个字节结束
swi2c_stop();
}
void swi2c_read_data(uint8_t device_addr,uint8_t *buf,uint8_t len)
{
swi2c_start();
swi2c_write_byte((device_addr) | 0x01);//读写位改为读
swi2c_wait_ack();
while(len > 1)
{
*buf++ = swi2c_read_byte();
swi2c_ack();
len--;
}
*buf = swi2c_read_byte();//循环体结束指针已经指向最后一个字节存放位置
swi2c_no_ack();//读一个字节结束
swi2c_stop();
}
#endif
iic.h
#ifndef __I2C_H__
#define __I2C_H__
#include "main.h"
#define I2C1_MODE_POLL 0x00
#define I2C1_MODE_INT 0x01
#define I2C1_MODE_DMA 0x02
#define I2C1_MODE_SLAVE 0x03
#define I2C1_MODE_SW 0x04
#define I2C1_MODE I2C1_MODE_SW
#define I2C1_SLAVE_ADDR 0xA0
#define I2C1_SPEED 100000
#if I2C1_MODE == I2C1_MODE_POLL
void i2c1_config(void);
void i2c1_write_data_by_reg(uint8_t slave_addr,uint8_t* p_buffer, uint8_t write_address, uint8_t number_of_byte);
void i2c1_read_data_by_reg(uint8_t slave_addr,uint8_t* p_buffer, uint8_t read_address, uint16_t number_of_byte);
#elif I2C1_MODE == I2C1_MODE_DMA
#define ARRAYNUM(arr_nanme) (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))
//#define I2C0_DATA_ADDRESS 0x40005410
#define I2C1_DATA_ADDRESS 0x40005810
#define I2C_TX_RX_DATA_LEN_MAX 128
void i2c1_dma_send_data(uint8_t slave_addr,uint8_t *reg_addr,uint16_t addr_len,uint8_t *p_data,uint8_t data_len);
void i2c1_dma_init();
void i2c1_dma_receive_data(uint8_t slave_addr, uint8_t *reg_addr,uint16_t addr_len,
uint8_t* p_buffer, uint16_t number_of_byte);
#elif I2C1_MODE == I2C1_MODE_SLAVE
#define I2C1_OWN_ADDRESS7 0x30
extern volatile uint8_t i2c_txbuffer[128];
extern volatile uint8_t i2c_rxbuffer[128];
void i2c1_slave_config(void);
#elif I2C1_MODE == I2C1_MODE_SW
void swi2c_config(void);
void swi2c_search_device_addr(void);
//针对eeprom使用
void swi2c_device_write_bytes(uint8_t device_addr,uint8_t reg_addr,uint8_t *buf,uint8_t len);
void swi2c_device_read_bytes(uint8_t device_addr,uint8_t reg_addr,uint8_t *buf,uint8_t len);
void swi2c_device_read_data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len,uint8_t *buf,uint8_t len);
void swi2c_device_write_data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len,uint8_t *buf,uint8_t len);
void swi2c_read_data(uint8_t device_addr,uint8_t *buf,uint8_t len);
void swi2c_write_data(uint8_t device_addr,uint8_t *buf,uint8_t len);
#endif // I2C1_MODE == I2C1_MODE_POLL
#endif //__I2C_H__
上边是IIC基本的驱动代码,接下来就是大头:
VEML7700.C
#include "main.h"
#include "veml7700.h"
#include "i2c.h"
#include <stdio.h>
void veml7700_write(uint8_t reg_addr,uint8_t *p_buf)
{
#if I2C1_MODE == I2C1_MODE_SW
swi2c_device_write_data(VEML_SLAVE_ADDR,®_addr,1,p_buf,2);
#endif
}
void veml7700_read(uint8_t reg_addr,uint8_t *p_buf)
{
#if I2C1_MODE == I2C1_MODE_SW
swi2c_device_read_data(VEML_SLAVE_ADDR,®_addr,1,p_buf,2);
#endif
}
static int get_veml7700_default_value(uint16_t *default_value)
{
uint8_t rx_data[2] = {0};
veml7700_read(0x00,rx_data);
*default_value = ((rx_data[1] << 8) | rx_data[0]);
return 0;
}
static uint16_t veml7700_get_light_sensor_value(uint8_t command,uint16_t mask,uint8_t shift)
{
uint8_t rx_data[2] = {0};
uint16_t r_value = 0;
veml7700_read(command,rx_data);
r_value = ((rx_data[1] << 8) | rx_data[0]);
return (r_value & mask) >> shift;
}
static void veml7700_set_light_sensor_value(uint8_t value,uint8_t command,uint16_t mask,uint8_t shift)
{
uint8_t rx_data[2] = {0};
uint8_t tx_data[2] = {0};
uint16_t r_value = 0;
uint16_t tmp_value = 0;
veml7700_read(command,rx_data);
r_value = ((rx_data[1] << 8) | rx_data[0]);
tmp_value = r_value & ~(mask);
tmp_value |= ((value << shift) & mask);
tx_data[0] = tmp_value & 0xff;
tx_data[1] = ((tmp_value >> 8) & 0xff);
veml7700_write(command,tx_data);
}
static uint16_t get_power_enable()
{
return veml7700_get_light_sensor_value(COMMAND_ALS_SD,ALS_SD_MASK,ALS_SD_SHIFT);
}
static void set_power_enable(int enable)
{
veml7700_set_light_sensor_value(enable,COMMAND_ALS_SD,ALS_SD_MASK,ALS_SD_SHIFT);
}
static uint16_t get_gain_value(void)
{
return veml7700_get_light_sensor_value(COMMAND_ALS_GAIN,ALS_GAIN_MASK,ALS_GAIN_SHIFT);
}
static void set_gain_value(uint16_t gain)
{
veml7700_set_light_sensor_value(gain,COMMAND_ALS_GAIN,ALS_GAIN_MASK,ALS_GAIN_SHIFT);
}
static uint16_t get_interrupt_enable(void)
{
return veml7700_get_light_sensor_value(COMMAND_ALS_INT_EN,ALS_INT_EN_MASK,ALS_INT_EN_SHIFT);
}
static void set_interrupt_enable(uint16_t enable)
{
veml7700_set_light_sensor_value(enable,COMMAND_ALS_INT_EN,ALS_INT_EN_MASK,ALS_INT_EN_SHIFT);
}
static int get_integration_time(void)
{
return veml7700_get_light_sensor_value(COMMAND_ALS_IT,ALS_IT_MASK,ALS_IT_SHIFT);
}
static void set_integration_time(int time)
{
veml7700_set_light_sensor_value(time,COMMAND_ALS_IT,ALS_IT_MASK,ALS_IT_SHIFT);
}
static int get_power_saving_mode(void)
{
return veml7700_get_light_sensor_value(COMMAND_PSM_EN,PSM_EN_MASK,PSM_EN_SHIFT);
}
static void set_power_saving_mode(int mode)
{
veml7700_set_light_sensor_value(mode,COMMAND_PSM_EN,PSM_EN_MASK,PSM_EN_SHIFT);
}
static uint16_t get_als_reg_data(void)
{
uint8_t rx_data[2] = {0};
uint16_t r_value = 0;
veml7700_read(COMMAND_ALS_DATA,rx_data);
r_value = ((rx_data[1] << 8) | rx_data[0]);
return r_value;
}
static float normalize_resolution(float value)
{
switch (get_gain_value())
{
case ALS_GAIN_X2:
value /= 2.0;
break;
case ALS_GAIN_d4:
value *= 4.0;
break;
case ALS_GAIN_d8:
value *= 8.0;
break;
case ALS_GAIN_X1:
default:break;
}
switch (get_integration_time()){
case ALS_INTEGRATION_25ms:
value *= 4;
break;
case ALS_INTEGRATION_50ms:
value *= 2;
break;
case ALS_INTEGRATION_200ms:
value *= 2.0;
break;
case ALS_INTEGRATION_400ms:
value *= 4.0;
break;
case ALS_INTEGRATION_800ms:
value *= 8.0;
break;
case ALS_INTEGRATION_100ms:
default:break;
}
return value;
}
float get_lux_data(void)
{
//gain value==2
// return normalize_resolution(get_als_reg_data() * 0.1152);//原有代码25ms
// return normalize_resolution(get_als_reg_data() * 0.0576);//原有代码50ms
// return normalize_resolution(get_als_reg_data() * 0.0288);//原有代码100ms
// return normalize_resolution(get_als_reg_data() * 0.0144);//原有代码200ms
return normalize_resolution(get_als_reg_data() * 0.0072);//原有代码400ms 这个比较准确
// return normalize_resolution(get_als_reg_data() * 0.0036);//原有代码800ms
}
void veml7700_init(void)
{
uint16_t default_value;
get_veml7700_default_value(&default_value);
if (default_value == 0x0001)
{
printf("Have Fined Veml7700!\r\n");
}
else
{
printf("Veml7700 not exsit %x\r\n",default_value);
}
set_power_enable(ALS_POWER_SHUTDOWN);
printf("get_power_enable %d\r\n",get_power_enable());
set_interrupt_enable(ALS_INTERRUPT_DISABLE);
set_gain_value(ALS_GAIN_d8);
printf("get_gain_value == %d\r\n",get_gain_value());
set_integration_time(ALS_INTEGRATION_400ms);//请修改这里表示精度 400比较准确
set_power_saving_mode(ALS_POWER_MODE_DISABLE);
set_power_enable(ALS_POWER_ON);
}
VEML7700.h
#ifndef __VEML_7700_H__
#define __VEML_7700_H__
#define ENABLE_VEML7700 0
#define VEML_SLAVE_ADDR 0x20
#define COMMAND_ALS_DEFAULT_VALUE 0x01
// 获得寄存器
#define COMMAND_ALS_GAIN 0x00
#define ALS_GAIN_MASK 0x1800
#define ALS_GAIN_SHIFT 11
// ALS IT寄存器
#define COMMAND_ALS_IT 0x00
#define ALS_IT_MASK 0x03C0
#define ALS_IT_SHIFT 6
// ALS持久寄存器
#define COMMAND_ALS_PER 0x00
#define ALS_PER_MASK 0x0030
#define ALS_PER_SHIFT 4
// ALS INT EN Register
#define COMMAND_ALS_INT_EN 0x00
#define ALS_INT_EN_MASK 0x0002
#define ALS_INT_EN_SHIFT 1
// ALS SD Register
#define COMMAND_ALS_SD 0x00
#define ALS_SD_MASK 0x0001
#define ALS_SD_SHIFT 0
// ALS Window High
#define COMMAND_ALS_WH 0x01
// ALS Window Low
#define COMMAND_ALS_WL 0x02
// ALS Power Save Mode
#define COMMAND_PSM 0x03
#define PSM_MASK 0x0006
#define PSM_SHIFT 1
// ALS Power Save Mode Enable
#define COMMAND_PSM_EN 0x03
#define PSM_EN_MASK 0x0001
#define PSM_EN_SHIFT 0
// ALS High Resolution Output Data
#define COMMAND_ALS_DATA 0x04
//White Channel Output Data
#define COMMAND_WHITE_DATA 0x05
// Interrupt Status
#define COMMAND_ALS_IF_L 0x06
#define ALS_IF_L_MASK 0x8000
#define ALS_IF_L_SHIFT 15
#define COMMAND_ALS_IF_H 0x06
#define ALS_IF_H_MASK 0x4000
#define ALS_IF_H_SHIFT 14
#define ALS_GAIN_X1 0x0
#define ALS_GAIN_X2 0x1
#define ALS_GAIN_d8 0x2
#define ALS_GAIN_d4 0x3
#define ALS_INTEGRATION_25ms 0xC
#define ALS_INTEGRATION_50ms 0x8
#define ALS_INTEGRATION_100ms 0x0
#define ALS_INTEGRATION_200ms 0x1
#define ALS_INTEGRATION_400ms 0x2
#define ALS_INTEGRATION_800ms 0x3
#define ALS_PERSISTENCE_1 0x0
#define ALS_PERSISTENCE_2 0x1
#define ALS_PERSISTENCE_4 0x2
#define ALS_PERSISTENCE_8 0x3
#define ALS_POWER_MODE_1 0x0
#define ALS_POWER_MODE_2 0x1
#define ALS_POWER_MODE_3 0x2
#define ALS_POWER_MODE_4 0x3
#define ALS_POWER_MODE_ENABLE 0x1
#define ALS_POWER_MODE_DISABLE 0x0
#define ALS_INTERRUPT_ENABLE 0x1
#define ALS_INTERRUPT_DISABLE 0x0
#define ALS_POWER_ON 0x0
#define ALS_POWER_SHUTDOWN 0x1
void veml7700_init(void);
float get_lux_data(void);
#endif
调用上面的驱动程序进行数据获取的示例,只贴出部分程序,其他不方便贴出,望谅解:
main.c
/* USER CODE BEGIN 2 */
veml7700_init();
OLED_Init();
OLED_ColorTurn(0);//0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显?
OLED_Refresh();
OLED_Clear();
HAL_Delay(10);
OLED_ShowString(0, 16 * 1, (u8 *)"max:", 16, 1);
OLED_ShowString(0, 16 * 2, (u8 *)"min:", 16, 1);
OLED_ShowString(0, 16 * 3, (u8 *)"val:", 16, 1);
OLED_ShowString(96, 16 * 1, (u8 *)"lux", 16, 1);
OLED_ShowString(96, 16 * 2, (u8 *)"lux", 16, 1);
OLED_ShowString(96, 16 * 3, (u8 *)"lux", 16, 1);
OLED_Refresh();
/* USER CODE END 2 */
while (1)
{
Light = get_lux_data();
printf("%.2f\r\n", Light);
//定时器定时每100ms采集数据
OLED_ShowNum(32, 48, Light, 5, 16, 1);//0~65535
Light=Light*100;
Light=(int)Light % 100;//获取后面两位小数点;
OLED_ShowString(72, 16 * 3, (u8 *)".", 16, 1);
OLED_ShowNum(76, 48, Light, 2, 16, 1);//0~65535
OLED_Refresh();//OLED显示数据
}