안녕하세요 오토입니다.
이번 메모 포스팅은 STM32F103 과 I2C를 사용하여 조도센서 BH1750 의 데이터를 확보하는 메모입니다.
일단 항상 마찬가지로 IDE 세팅 해줍니다.
인터럽트 켜주구요
GPIO까지 세팅해주고 나면 끝납니다.
다음으로는 관련 헤더파일과 소스파일 생성해주고 코드 넣어줍니다.
헤더파일.
#ifndef INC_BH1750_H_
#define INC_BH1750_H_
//Device Address
//Please note that arduino uses 7 bit addresses, STM32 uses 8
#define BH1750_NO_GROUND_ADDR_WRITE (0xB9 + 0)
#define BH1750_NO_GROUND_ADDR_READ (0xB9 + 1)
#define BH1750_GROUND_ADDR_WRITE (0x46 + 0)
#define BH1750_GROUND_ADDR_READ (0x46 + 1)
//instructions
//datasheet ref http://cpre.kmutnb.ac.th/esl/learning/bh1750-light-sensor/bh1750fvi-e_datasheet.pdf
#define CMD_POWER_DOWN 0x00
#define CMD_POWER_ON 0x01
#define CMD_RESET 0x03
#define CMD_H_RES_MODE 0x10
#define CMD_H_RES_MODE2 0x11
#define CMD_L_RES_MODE 0x13
#define CMD_ONE_H_RES_MODE 0x20
#define CMD_ONE_H_RES_MODE2 0x21
#define CMD_ONE_L_RES_MODE 0x23
#define CMD_CNG_TIME_HIGH 0x30 // 3 LSB set time
#define CMD_CNG_TIME_LOW 0x60 // 5 LSB set time
#ifndef bool
#define bool uint8_t
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
void BH1750_Init();
//void BH1750_ReadData(uint8_t *data);
void BH1750_ReadData(uint8_t *data);
void BH1750_run(uint8_t *data);
extern uint8_t data[2];
extern uint8_t cmd;
extern uint16_t val;
extern HAL_StatusTypeDef ret;
extern float lighting_c;
typedef struct BH1750_device BH1750_device_t;
struct BH1750_device{
char* name;
I2C_HandleTypeDef* i2c_handle;
uint8_t address_r;
uint8_t address_w;
uint16_t value;
uint8_t buffer[2];
uint8_t mode;
void (* poll)(BH1750_device_t*);
} ;
HAL_StatusTypeDef BH1750_read_dev(BH1750_device_t* dev);
HAL_StatusTypeDef BH1750_init_i2c(I2C_HandleTypeDef* i2c_handle);
BH1750_device_t* BH1750_init_dev_struct(I2C_HandleTypeDef* i2c_handle,
char* name, bool addr_grounded);
HAL_StatusTypeDef BH1750_init_dev(BH1750_device_t* dev);
HAL_StatusTypeDef BH1750_get_lumen(BH1750_device_t* dev);
#endif /* INC_BH1750_H_ */
소스파일.
#define BH1750_ADDR_LOW 0x23 <<1 // BH1750?�� LOW 주소
#define BH1750Address 0x23
#define BH1750_CMD_POWER_ON 0x01
#define BH1750_CMD_RESET 0x07
#define BH1750_CMD_CONT_HRES 0x10 // ?��?�� 모드?? H-Resolution 모드 ?��?��
uint8_t data[2];
uint8_t buff[3];
uint8_t cmd;
uint16_t val =0;
HAL_StatusTypeDef ret;
float lighting_c;
void BH1750_run(uint8_t *data)
{
if(bh1750_time_flag == 1)
{
BH1750_ReadData(data);
bh1750_time_flag = 0;
}
}
//i2c_BH1750
void BH1750_Init()
{
HAL_GPIO_WritePin(LI_ADDR_GPIO_Port, LI_ADDR_Pin, GPIO_PIN_RESET);//Lighting sensor I2C Address Low
HAL_GPIO_WritePin(LI_DVI_EN_GPIO_Port, LI_DVI_EN_Pin, GPIO_PIN_SET);//Lighting sensor I2C DVI ENABLE
BH1750_device_t* test_dev = BH1750_init_dev_struct(&hi2c1, "test device", true);
BH1750_init_dev(test_dev);
printf("BH1750_init_OK\r\n");
}
void BH1750_ReadData(uint8_t *data)
{
uint8_t buff[3];
uint16_t val = 0;
HAL_I2C_Master_Receive(&hi2c1, (BH1750Address << 1) | 0x01, buff, 2, 500);
val = (uint16_t)(((buff[0] << 8) | buff[1]) / 1.2);
printf("i2c val : %d\r\n",val);
}
void _Error_Handler(char * file, int line)
{
while(1)
{
}
}
HAL_StatusTypeDef BH1750_init_i2c(I2C_HandleTypeDef* i2c_handle)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
i2c_handle->Instance = I2C1;
i2c_handle->Init.ClockSpeed = 100000;
i2c_handle->Init.DutyCycle = I2C_DUTYCYCLE_2;
i2c_handle->Init.OwnAddress1 = 0;
i2c_handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
i2c_handle->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
i2c_handle->Init.OwnAddress2 = 0;
i2c_handle->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
i2c_handle->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(i2c_handle) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
return HAL_OK;
}
HAL_StatusTypeDef BH1750_send_command(BH1750_device_t* dev, uint8_t cmd)
{
//TODO hal checks
if(HAL_I2C_Master_Transmit(
dev->i2c_handle, //I2C Handle
dev->address_w, //I2C addr of dev
&cmd, //CMD to be executed
1, //8bit addr
10 //Wait time
) != HAL_OK) return HAL_ERROR;
return HAL_OK;
}
void BH1750_poll_self(BH1750_device_t* self)
{
BH1750_get_lumen(self);
}
BH1750_device_t* BH1750_init_dev_struct(I2C_HandleTypeDef* i2c_handle,char* name, bool addr_grounded)
{
BH1750_device_t* init =
(BH1750_device_t*)calloc(1, sizeof(BH1750_device_t));
if(init == NULL) return NULL;
if(addr_grounded){
init->address_r = BH1750_GROUND_ADDR_READ;
init->address_w = BH1750_GROUND_ADDR_WRITE;
}else{
init->address_r = BH1750_NO_GROUND_ADDR_READ;
init->address_w = BH1750_NO_GROUND_ADDR_WRITE;
}
init->name = (char*)malloc(sizeof(char) * strlen(name));
if(init->name == NULL) return NULL;
init->i2c_handle = i2c_handle;
strcpy(init->name, name);
init->poll = &BH1750_poll_self;
return init;
}
HAL_StatusTypeDef BH1750_init_dev(BH1750_device_t* dev)
{
BH1750_send_command(dev, CMD_POWER_ON);
BH1750_send_command(dev, CMD_RESET);
BH1750_send_command(dev, CMD_H_RES_MODE);
return HAL_OK;
}
HAL_StatusTypeDef BH1750_read_dev(BH1750_device_t* dev)
{
if(HAL_I2C_Master_Receive(dev->i2c_handle,
dev->address_r,
dev->buffer,
2,
10
) != HAL_OK) return HAL_ERROR;
return HAL_OK;
}
HAL_StatusTypeDef BH1750_convert(BH1750_device_t* dev)
{
dev->value = dev->buffer[0];
dev->value = (dev->value << 8) | dev->buffer[1];
//TODO check float stuff
dev->value/=1.2;
return HAL_OK;
}
HAL_StatusTypeDef BH1750_get_lumen(BH1750_device_t* dev)
{
BH1750_read_dev(dev);
BH1750_convert(dev);
return HAL_OK;
}
1. 먼저 INIT 진행해줍니다.
- i2c는 어드레스가 필요하니까 sensor에서 어드레스 세팅될 수 있도록 gpio 먼저 low or high 세팅해주고
-센서 enable 시키는 핀 high 해줍니다.
-다음은 헤더파일에 define 된 struct fmf rename 하여 선언해주고 주고, 모드, 등등을
BH1750_init_dev_struct(&hi2c1, "test device", true);
뒤에 함수로 떼려 박아 넣을 수 있게 해주고
이걸 바탕으로 최종 init 을 해줍니다.
BH1750_init_dev(test_dev);
이렇게 되면 init은 마무리됩니다. struct 사용되고 하니 따라 들어가서 보고 하나씩 이해하시면 간결하게 앞에서는 두줄이면 끝나구요
void BH1750_ReadData(uint8_t *data)
{
uint8_t buff[3];
uint16_t val = 0;
HAL_I2C_Master_Receive(&hi2c1, (BH1750Address << 1) | 0x01, buff, 2, 500);
val = (uint16_t)(((buff[0] << 8) | buff[1]) / 1.2);
printf("i2c val : %d\r\n",val);
}
다음은 그냥 read 함수로 받아서 버퍼에 떼려넣고 비트 쉬프트 시키는 등등 계산해줍니다.
센서 데이터시트보시면 나와있으니 참고하시면 되구요.
void BH1750_run(uint8_t *data)
{
if(bh1750_time_flag == 1)
{
BH1750_ReadData(data);
bh1750_time_flag = 0;
}
}
메인 run 함수 하나 만들어서 타이머 플래그 뜰때마다 돌립니다.
잘돌아가네요 단위가 룩스인데 사무실이 이렇게 밝은지 ... 시정수 넣어서 좀 계산해주시거나 하면 될거같구요
#define CMD_POWER_DOWN 0x00
#define CMD_POWER_ON 0x01
#define CMD_RESET 0x03
#define CMD_H_RES_MODE 0x10
#define CMD_H_RES_MODE2 0x11
#define CMD_L_RES_MODE 0x13
#define CMD_ONE_H_RES_MODE 0x20
#define CMD_ONE_H_RES_MODE2 0x21
#define CMD_ONE_L_RES_MODE 0x23
#define CMD_CNG_TIME_HIGH 0x30 // 3 LSB set time
#define CMD_CNG_TIME_LOW 0x60
헤더파일에 다양한 모드하고 power on/off 레지스터 주소들 있으니까 활용하시면될것같구요
그럼이만 오늘도 대단히 맛있는거 많이드시고 이만.
'STM32 > STM32F' 카테고리의 다른 글
STM32F103 - ADC DMA 읽어오기 (0) | 2023.12.09 |
---|---|
STM32F103 - TIMER 인터럽트 만들기 (0) | 2023.12.02 |
STM32F103 - UART DMA로 문자열 한번에 받기 (4) | 2023.11.25 |
STM32F103 - GPIO 외부 인터럽드 설정 및 동작 (0) | 2023.11.18 |
stm32cubeIDE 외부 헤더 및 소스 파일 추가하기 (3) | 2023.11.11 |
댓글