์ด ์ ๊ธ์์ AM1008W-K-P ๋ฐ์ดํฐ์ํธ์ I2C HAL ํจ์๋ค์ ์๊ฐํ๋ค. ์ด๋ฒ ๊ธ์ ์ ์ ๋ณด๋ค์ ์ด์ฉํ์ฌ ์๋์ด๋ ธ์ ๋๊ฐ์ด ์ฌํํ๋๋ก ํ๊ฒ ๋ค. ์ฐ์ ํ๋ก์ ํธ๋ฅผ ์์ฑํ๋ค. ํ๋ก์ ํธ ์์ฑ์ ๋ํ ๋ด์ฉ์ ์๋ตํ๊ฒ ๋ค.
1. I2C ์ค์
I2C ๋์์ ๊ตฌํํ๊ธฐ ์ํด ๋ ์ง์คํฐ๋ฅผ ์ค์ ํด์ฃผ์ด์ผ ํ๋๋ฐ, CUBE IDE์์๋ ๊ฐ๋จํ๊ฒ GUI๋ฅผ ํตํด ์์ฑํ ์ ์๋ค.
I2C1์ USART1์ ๊ฐ๊ฐ ํ์ฑํ์ํจ๋ค. (์๋ต, ์ด ์ ๊ธ๋ค ์ฐธ๊ณ ๋ฐ๋)
USART1๋ ๊ธฐ๋ณธ 115200์ ์ฌ์ฉํ ๊ฒ์ด๋ฏ๋ก ๋ณ๋์ ์ค์ ์ ํ ํ์๋ ์์ง๋ง I2C1์ ์๋๋ฅผ ์ค์ ํด์ฃผ์ด์ผ ํ๋ค.
AM1008W-K-P ์ผ์๋ 30kbps ์ดํ์์ ๋์ํ๋ ๊ฒ์ด ์คํ์ด๋ค.
I2C1์ default ์ค์ ์ผ๋ก standard ๋ชจ๋๋ก 100kbps์ด๋ค.
100kbps๋ ์ค๋ฒ ์คํผ๋์ด๋ฏ๋ก ํต์ ์๋๋ฅผ ์คํ๋๋ก ๋ฎ์ถ ํ์๊ฐ ์๋ค.
I2C Speed๋ฅผ 30,000Hz๋ก ๋ณ๊ฒฝํ๋ค.
STM32F103์ ๋ง์คํฐ๋ก ๋์ํ๊ธฐ ๋๋ฌธ์ Slave Features๋ ๊ฑด๋๋ฆด ํ์๊ฐ ์๋ค.
GPIO ์ค์ ์ผ๋ก ๋ค์ด๊ฐ I2C Maximum output ์คํผ๋๊ฐ ๊ธฐ๋ณธ High๋ก ๋์ด ์๋๋ฐ Medium์ด๋ Low ๋ก ๋จ์ถฐ์ฃผ์ด์ผ ํ๋ค.
ํด๋น ํ๋งต์ ํตํด ๋ด์ฅ GPIO Pull-up์ด ์๊ธฐ์ ์ธ์ฅ Pull-up ์ ํญ์ ์จ์ผํ๋ ๊ฒ์ ์ ์ ์๋ค.
์ด๋ ๊ฒ ๋๋ฉด ์ค์ ์ ์๋ฃ๋์๊ณ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
์ฌ๊ธฐ์ UART๋ฅผ ํ์ฑํํ ์ด์ ๋ UART to Serial ์ ํตํด ์ปดํจํฐ์์ ๊ฐ์ ํ์ธํ๊ธฐ ์ํด์์ด๋ค.
2. AM1008W-P-K ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์ฐ๋ฆฌ๋ ์๋์ด๋
ธ ๊ธ์์ AM1008W-K-P๋ฅผ ํ
์คํธํ์๋ค.
์ด์ด ์ข๊ฒ๋ github์ ์ฝ๋(์๋์ด๋
ธ + C++)๋ค์ด ์ฌ๋ผ์ ์์๊ณ ์ฐ๋ฆฌ๋ ์ด๋ฅผ STM32 + C์ธ์ด๋ก ๋ณ๊ฒฝํด์ฃผ๋ฉด ๋๋ค.
์ฌ๊ธฐ์ ํ ํ๋.
https://github.com/neosarchizo/am1008w_k_i2c/tree/main/src
์ด์ ๊ฐ๋ฐ์๋ค๋ ์กฐ๊ธ ๊ฐ๋ฐํ๋ ์คํ์ผ์ ์กฐ๊ธ ์ค๋งํธํ๊ฒ ๊ฐ์ ธ๊ฐ ํ์๊ฐ ์๋ค.
๊ทธ๊ฒ์ ๋ฐ๋ก chatgpt ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์ฐ๋ฆฌ๋ C++๋ก ์ค๊ณ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ C์ธ์ด๋ก ๋ณ๊ฒฝํด์ผ ํ๋๋ฐ GPT์๊ฒ ๋์ง๋ฉด ๊ฐ๋จํ ๋ณ๊ฒฝํ ์ ์๋ค. (๋๋ GPT4๋ฅผ ์ฌ์ฉํ๋๋ฐ 3.5๋ ์ฑ๋ฅ์ด ์ด๋์ ๋ ์ธ์ง๋ ์๋ชจ๋ฅด๊ฒ ๋ค.)
๋ฐฉ๋ฒ์ ๊ฐ๋จํ๋ค. ์ฝ๋๋ฅผ ๊ทธ๋๋ก ๋์ ธ์ ๋ณ๊ฒฝํด๋ฌ๋ผ๊ณ ํ๋ฉด ๋๋ค. ์ฌ์ํ ๋ด์ฉ๋ค์ debugํ๋ฉด ๋๋ค.
gpt๊ฐ c์ธ์ด๋ก ๋ณ๊ฒฝํ ์์ค์ฝ๋๋ค์ด๋ค.
3. am1008w_k_i2c.h
/*
* am1008w_k_i2c.h
*
* Created on: Jul 17, 2024
* Author: Yoon
*/
#ifndef SRC_AM1008W_K_I2C_H_
#define SRC_AM1008W_K_I2C_H_
#include <stdint.h>
#include "main.h"
#define AM1008W_K_I2C_ADDRESS 0x28
#define AM1008W_K_I2C_FRAME_STX 0x16
#define AM1008W_K_I2C_LEN_READ_DATA_COMMAND 25
#define AM1008W_K_I2C_PSO_CLOSE 0x00
#define AM1008W_K_I2C_PSO_TIMING_MEASURING_MODE 0x05
#define AM1008W_K_I2C_PSO_DYNAMIC_MEASURING_MODE 0x06
#define AM1008W_K_I2C_PSO_CONTINOUS_MEASURING_MODE 0x0C
#define AM1008W_K_I2C_PSO_SINGLE_MEASURING_MODE 0x0D
#define AM1008W_K_I2C_CTRL_CLOSE_MEASUREMENT 0x01
#define AM1008W_K_I2C_CTRL_OPEN_MEASUREMENT 0x02
#define AM1008W_K_I2C_CTRL_CO2_CALIBRATION 0x03
#define AM1008W_K_I2C_CTRL_SET_UP_TIMING_MEASUREMENT 0x05
#define AM1008W_K_I2C_CTRL_SET_UP_DYNAMIC_MEASUREMENT 0x06
#define AM1008W_K_I2C_CTRL_SET_UP_PM_CALIBRATION_COEFFICIENT 0x07
#define AM1008W_K_I2C_CTRL_SET_UP_CONTINUOUSLY_MEASUREMENT 0x0C
#define AM1008W_K_I2C_CTRL_SET_UP_SINGLE_MEASUREMENT 0x0D
typedef union
{
uint8_t value;
struct
{
uint8_t fan_at_high_revolving_speed:1;
uint8_t fan_at_low_revolving_speed:1;
uint8_t working_temperature_is_high:1;
uint8_t working_temperature_is_low:1;
} bits;
} am1008w_k_i2c_status;
#ifdef __cplusplus
extern "C" {
#endif
void am1008w_k_i2c_begin(I2C_HandleTypeDef *hi2c);
uint8_t am1008w_k_i2c_pm_sensor_mode_close();
uint8_t am1008w_k_i2c_pm_sensor_mode_open();
uint8_t am1008w_k_i2c_pm_sensor_mode_single_measurement(uint16_t range);
uint8_t am1008w_k_i2c_pm_sensor_mode_continuously_measurement();
uint8_t am1008w_k_i2c_pm_sensor_mode_timing_measurement(uint16_t range);
uint8_t am1008w_k_i2c_pm_sensor_mode_dynamic_measurement();
uint8_t am1008w_k_i2c_set_pm_coefficient(uint8_t range);
uint8_t am1008w_k_i2c_calibrate_co2(uint16_t range);
uint8_t am1008w_k_i2c_read_data_command();
uint8_t am1008w_k_i2c_get_pm_operation_mode();
uint16_t am1008w_k_i2c_get_co2();
uint16_t am1008w_k_i2c_get_voc();
int am1008w_k_i2c_get_humidity();
int am1008w_k_i2c_get_temperature();
uint16_t am1008w_k_i2c_get_pm1p0();
uint16_t am1008w_k_i2c_get_pm2p5();
uint16_t am1008w_k_i2c_get_pm10();
uint16_t am1008w_k_i2c_get_voc_now_r_ref_r();
uint16_t am1008w_k_i2c_get_voc_ref_r();
uint16_t am1008w_k_i2c_get_voc_now_r();
am1008w_k_i2c_status am1008w_k_i2c_get_pm_sensor_status_alarm();
#ifdef __cplusplus
}
#endif
#endif /* SRC_AM1008W_K_I2C_H_ */
4. am1008w_k_i2c.c
/*
* am1008w_k_i2c.c
*
* Created on: Jul 17, 2024
* Author: Yoon
*/
#include "am1008w_k_i2c.h"
static I2C_HandleTypeDef *mhi2c;
static uint8_t _buffer[32];
static uint8_t _pm_operation_mode;
static uint16_t _co2;
static uint16_t _voc;
static int _humidity;
static int _temperature;
static uint16_t _pm1p0;
static uint16_t _pm2p5;
static uint16_t _pm10;
static uint16_t _voc_now_r_ref_r;
static uint16_t _voc_ref_r;
static uint16_t _voc_now_r;
static am1008w_k_i2c_status _pm_sensor_status_alarm;
void am1008w_k_i2c_begin(I2C_HandleTypeDef *hi2c) {
mhi2c = hi2c;
}
uint8_t am1008w_k_i2c_send_command_data(uint8_t ctrl, uint16_t data) {
uint8_t tx_data[7] = {0};
tx_data[0] = AM1008W_K_I2C_FRAME_STX;
tx_data[1] = 7; // FRAME LENGTH
tx_data[2] = ctrl; // Control Command of the PM Sensor
tx_data[3] = (data >> 8) & 0xff; // high byte of data
tx_data[4] = data & 0xff; // low byte of data
tx_data[5] = 0;
uint8_t cs = tx_data[0];
for (uint8_t i = 1; i < 6; i++) {
cs ^= tx_data[i];
}
tx_data[6] = cs;
HAL_I2C_Master_Transmit(mhi2c, AM1008W_K_I2C_ADDRESS << 1, tx_data, 7, HAL_MAX_DELAY);
return 0;
}
uint8_t am1008w_k_i2c_pm_sensor_mode_close() {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_CLOSE_MEASUREMENT, 0);
}
uint8_t am1008w_k_i2c_pm_sensor_mode_open() {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_OPEN_MEASUREMENT, 0);
}
uint8_t am1008w_k_i2c_pm_sensor_mode_single_measurement(uint16_t range) {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_SET_UP_SINGLE_MEASUREMENT, range);
}
uint8_t am1008w_k_i2c_pm_sensor_mode_continuously_measurement() {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_SET_UP_CONTINUOUSLY_MEASUREMENT, 0);
}
uint8_t am1008w_k_i2c_pm_sensor_mode_timing_measurement(uint16_t range) {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_SET_UP_TIMING_MEASUREMENT, range);
}
uint8_t am1008w_k_i2c_pm_sensor_mode_dynamic_measurement() {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_SET_UP_DYNAMIC_MEASUREMENT, 0);
}
uint8_t am1008w_k_i2c_set_pm_coefficient(uint8_t range) {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_SET_UP_PM_CALIBRATION_COEFFICIENT, range);
}
uint8_t am1008w_k_i2c_calibrate_co2(uint16_t range) {
return am1008w_k_i2c_send_command_data(AM1008W_K_I2C_CTRL_CO2_CALIBRATION, range);
}
uint8_t am1008w_k_i2c_read_data_command() {
HAL_I2C_Master_Receive(mhi2c, (AM1008W_K_I2C_ADDRESS << 1) | 1, _buffer, 25, HAL_MAX_DELAY);
uint8_t idx = 0;
if (_buffer[0] != AM1008W_K_I2C_FRAME_STX) {
return 2; // Frame header different
}
if (_buffer[1] != AM1008W_K_I2C_LEN_READ_DATA_COMMAND) {
return 3; // Frame length different
}
uint8_t check_code = _buffer[0];
for (uint8_t i = 1; i < AM1008W_K_I2C_LEN_READ_DATA_COMMAND - 1; i++) {
check_code ^= _buffer[i];
}
if (_buffer[AM1008W_K_I2C_LEN_READ_DATA_COMMAND - 1] != check_code) {
return 4; // Checksum wrong
}
_pm_operation_mode = _buffer[2];
_co2 = (_buffer[3] << 8) + _buffer[4];
_voc = (_buffer[5] << 8) + _buffer[6];
_humidity = ((_buffer[7] << 8) + _buffer[8]);
_temperature = ((_buffer[9] << 8) + _buffer[10] - 500);
_pm1p0 = (_buffer[11] << 8) + _buffer[12];
_pm2p5 = (_buffer[13] << 8) + _buffer[14];
_pm10 = (_buffer[15] << 8) + _buffer[16];
_voc_now_r_ref_r = (_buffer[17] << 8) + _buffer[18];
_voc_ref_r = (_buffer[19] << 8) + _buffer[20];
_voc_now_r = (_buffer[21] << 8) + _buffer[22];
_pm_sensor_status_alarm.value = _buffer[23];
return 0;
}
uint8_t am1008w_k_i2c_get_pm_operation_mode() {
return _pm_operation_mode;
}
uint16_t am1008w_k_i2c_get_co2() {
return _co2;
}
uint16_t am1008w_k_i2c_get_voc() {
return _voc;
}
int am1008w_k_i2c_get_humidity() {
return _humidity;
}
int am1008w_k_i2c_get_temperature() {
return _temperature;
}
uint16_t am1008w_k_i2c_get_pm1p0() {
return _pm1p0;
}
uint16_t am1008w_k_i2c_get_pm2p5() {
return _pm2p5;
}
uint16_t am1008w_k_i2c_get_pm10() {
return _pm10;
}
uint16_t am1008w_k_i2c_get_voc_now_r_ref_r() {
return _voc_now_r_ref_r;
}
uint16_t am1008w_k_i2c_get_voc_ref_r() {
return _voc_ref_r;
}
uint16_t am1008w_k_i2c_get_voc_now_r() {
return _voc_now_r;
}
am1008w_k_i2c_status am1008w_k_i2c_get_pm_sensor_status_alarm() {
return _pm_sensor_status_alarm;
}
5. main.c
#include "main.h"
#include am1008w_k_i2c.h
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
...
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
am1008w_k_i2c_begin(&hi2c1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
char buffer[100];
while (1)
{
am1008w_k_i2c_read_data_command();
int humidity = am1008w_k_i2c_get_humidity();
int temperature = am1008w_k_i2c_get_temperature();
uint16_t voc = am1008w_k_i2c_get_voc();
uint16_t co2 = am1008w_k_i2c_get_co2();
uint16_t pm1p0 = am1008w_k_i2c_get_pm1p0();
uint16_t pm2p5 = am1008w_k_i2c_get_pm2p5();
uint16_t pm10 = am1008w_k_i2c_get_pm10();
sprintf(buffer, "Humidity: %d.%02d %%, Temperature: %d.%02d C\r\n",
humidity / 10, humidity % 10, temperature / 10, temperature % 10);
HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 1000);
sprintf(buffer, "CO2: %d ppm, VOC: %d ppb, PM1.0: %d, PM2.5: %d, PM10: %d\r\n",
co2, voc, pm1p0, pm2p5, pm10);
HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 1000);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
์์ GPT๊ฐ ์์ฑํด์ค ์ฝ๋๋ฅผ ๊ทธ๋๋ก ๊ฐ๋ค์ด๊ฑด ์๋๊ณ , ๋ด๊ฐ ์ด๋ ์ ๋ ๋๋ฒ๊น ์ ํ ์ฝ๋๋ค์ด๋ค.
6. ํ๋ก ๊ตฌ์ฑ
์ด ํ๋ก์ ๋๊ฐ์ด ๊ตฌ์ฑ์ ํด์ฃผ์๋ค. ๋ค๋ง 10K์ด์ 4.7K์ด์ผ๋ก ๋์ฒดํ์๋ค. (์ธ๋ถ ํ์ ์ ํญ์ ์ฌ์ฉํด์ผ ํจ.)
7. ๋์ ํ์ธ
์ ์์ ์ผ๋ก ๋์ํ๋ ๊ฒ์ ํ์ธํ์์ผ๋ฉฐ ๋ชจ๋ํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ ๋๋ก ์ถ๋ ฅ๋๋ ๊ฒ์ ํ์ธํ๋ค.
https://youtube.com/shorts/TRYy-_zhIGg?si=BBddmJtvnHsqUXOM
๋ค์ ๊ธ๋ก๋ FTDI ๋ฅผ ๋ธ๋ฃจํฌ์ค๋ก ๋์ฒดํ๊ณ , ํ์ฌ String์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ํ์ถํ๋๋ฐ ํจํท์ ์ ์ฝํ ์ ์๊ฒ๋ ์ฝ๋๋ฅผ ๋ณ๊ฒฝํ ์์ ์ด๋ค.
๋ํ ๋ธ๋ฃจํฌ์ค๋ ๋ฌด์ ํต์ ์ด๋ ๊ทธ ํจํท์ ๊ฐ๋ฅํ๋ค๋ฉด Checksum ๋ก์ง์ ์ถ๊ฐํ์ฌ ๋ฐ์ดํฐ์ ์ ๋ขฐ์ฑ์ ๋์ฌ๋ณผ ๊ฒ์ด๋ค.
๋ด๊ฐ ์์ฑํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฒจ๋ถํ์ผ๋ก ์ถ๊ฐํด๋์ผ๋ ์ฐธ๊ณ ํ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
'๐ง STM32' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[STM32] 17. I2C ํต์ ํจ์ ์ข ๋ฅ (0) | 2024.12.05 |
---|---|
[STM32] 16. I2C ์ผ์ ์๊ฐ (๋ฏธ์ธ๋จผ์ง/์ด์ฐํํ์ ๋ณตํฉ ๊ณต๊ธฐ์ง ์ผ์ CUBIC - AM1008W-K-P) (0) | 2024.12.04 |
[STM32] 15. I2C ํต์ ๊ฐ์ (0) | 2024.12.04 |
[STM32] 14. ์ฝ๋ฐฑ ํจ์ ํธ์ถ ๊ณผ์ (0) | 2024.11.30 |
[STM32] 13. UART Interrupt ๊ตฌํ (0) | 2024.11.30 |