Browse Source

Switched to AHTxx.

Vladimir N. Shilov 1 year ago
parent
commit
84d0994968
8 changed files with 532 additions and 24 deletions
  1. 2 3
      .vscode/c_cpp_properties.json
  2. 0 0
      .vscode/settings.json
  3. 2 0
      ReadMe.txt
  4. 236 0
      lib/i2c.c
  5. 45 0
      lib/i2c.h
  6. 206 0
      lib/sensor.c
  7. 25 0
      lib/sensor.h
  8. 16 21
      src/main.c

+ 2 - 3
.vscode/c_cpp_properties.json

@@ -5,7 +5,8 @@
             "name": "VAXL",
             "defines": [
                 "STM8S003=",
-                "USE_STDPERIPH_DRIVER="
+                "USE_STDPERIPH_DRIVER=",
+                "_IAR_="
             ],
             "includePath": [
                 "${workspaceRoot}/inc/*",
@@ -14,8 +15,6 @@
                 "C:/IAR/Embedded Workbench 8.3/stm8/inc/**"
             ],
             "forcedInclude": [],
-            "cStandard": "gnu17",
-            "cppStandard": "c++17",
             "intelliSenseMode": "windows-gcc-arm",
             "configurationProvider": "ms-vscode.makefile-tools",
             "browse": {

+ 0 - 0
.vscode/settings.json


+ 2 - 0
ReadMe.txt

@@ -1 +1,3 @@
 Спроба приєднати сенсор AHTxx та виводити температуру та вологість.
+
+На пробу взяв ще інакший драйвер I2C, але в ньому немає заплатки від Errata.

+ 236 - 0
lib/i2c.c

@@ -0,0 +1,236 @@
+/**
+  \file i2c.h
+   
+  \author G. Icking-Konert
+  \date 2013-11-22
+  \version 0.1
+   
+  \brief implementation of I2C functions/macros
+   
+  implementation of functions for I2C bus communication
+  For I2C bus, see http://en.wikipedia.org/wiki/I2C
+*/
+
+/*-----------------------------------------------------------------------------
+    INCLUDE FILES
+-----------------------------------------------------------------------------*/
+#include "stm8s.h"
+
+/*-----------------------------------------------------------------------------
+    DEFINITION OF GLOBAL MACROS/#DEFINES
+-----------------------------------------------------------------------------*/
+#define I2C_FAST        1
+#define F_MASTER_MHZ    16UL
+#define F_MASTER_HZ     16000000UL
+#ifdef I2C_FAST
+//400 kHz
+#define F_I2C_HZ        400000UL
+#else
+//100 kHz
+#define F_I2C_HZ        100000UL
+#endif // I2C_FAST
+
+//CCR = Fmaster/2*Fiic = 16MHz/2*100kHz = 80
+#define CCR (uint16_t)(F_MASTER_HZ / (2 * F_I2C_HZ))
+
+/* Таймаут ожидания события I2C */
+extern __IO uint8_t I2C_timeout;
+
+/*----------------------------------------------------------
+    FUNCTIONS
+----------------------------------------------------------*/
+static uint8_t i2c_read(void);
+
+/**
+  \fn void i2c_init(void)
+  \brief configure I2C bus
+  configure I2C bus as master in standard mode, BR=100kHz, 7bit address, 250ns rise time
+*/
+void i2c_init() {
+  //Частота тактирования периферии MHz
+  I2C->FREQR = (uint8_t)(F_MASTER_MHZ);
+
+  //Отключаем I2C
+  I2C->CR1 &= (uint8_t)(~I2C_CR1_PE);
+
+  //Выбираем режим
+#ifdef I2C_FAST
+  I2C->CCRH = I2C_CCRH_FS; // | I2C_CCRH_DUTY;
+#else
+  I2C->CCRH = 0;
+#endif
+
+  //Set Maximum Rise Time: 1000ns max in Standard Mode
+  //= [1000ns/(1/InputClockFrequencyMHz.10e6)]+1
+  //= InputClockFrequencyMHz+1
+  I2C->TRISER = (uint8_t)(F_MASTER_MHZ + 1);
+  I2C->CCRL = (uint8_t)CCR;
+  I2C->CCRH |= (uint8_t)((uint8_t)(CCR >> 8) & I2C_CCRH_CCR);
+
+  //Включаем I2C
+  I2C->CR1 |= I2C_CR1_PE;
+
+  //Разрешаем подтверждение в конце посылки
+  I2C->CR2 |= I2C_CR2_ACK;
+} // i2c_init
+
+/**
+  \fn uint8_t i2c_waitFree(void)
+  \brief wait until bus is free
+  \return error code (0=ok; 1=timeout)
+  wait until bus is free with timeout
+*/
+uint8_t i2c_waitFree() {
+  // wait until bus free with timeout
+  I2C_timeout = 10;
+  while (((I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);
+ 
+  // on I2C timeout return error
+  if ((I2C->SR3 & I2C_SR3_BUSY)) {
+    i2c_init();
+    return(1);
+  }
+  
+  // return success
+  return(0);
+} // i2c_waitFree
+
+/**
+  \fn uint8_t i2c_start(void)
+  \brief generate I2C start condition
+  \return error code (0=ok; 1=timeout)
+  generate I2C start condition with timeout
+*/
+uint8_t i2c_start() {
+  // wait until bus free with timeout
+  I2C_timeout = 10;
+  while (((I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);
+ 
+  // on I2C timeout return error
+  if ((I2C->SR3 & I2C_SR3_BUSY)) {
+    i2c_init();
+    return(2);
+  }
+
+  // generate start condition with timeout
+  I2C->CR2 |= I2C_CR2_START;
+  I2C_timeout = 10;
+  while (!(I2C->SR1 & I2C_SR1_SB) && I2C_timeout);
+ 
+  // on I2C timeout return error
+  if (!(I2C->SR1 & I2C_SR1_SB)) {
+    i2c_init();
+    return(1);
+  }
+
+  // return success
+  return(0);
+} // i2c_start
+
+/**
+  \fn uint8_t i2c_stop(void)
+  \brief generate I2C stop condition
+  \return error code (0=ok; 1=timeout)
+  generate I2C stop condition with timeout 
+*/
+uint8_t i2c_stop() {
+  // generate stop condition with timeout
+  I2C->CR2 |= I2C_CR2_STOP;
+  I2C_timeout = 10;
+  while ((I2C->SR3 & I2C_SR3_MSL) && I2C_timeout);
+ 
+  // on I2C timeout set error flag
+  if (I2C->SR3 & I2C_SR3_MSL) {
+    i2c_init();
+    return(1);
+  }
+  
+  // return success
+  return(0);
+} // i2c_stop
+
+/**
+  \fn uint8_t i2c_send(uint8_t addr, uint8_t numTx, uint8_t *bufTx)
+  \brief write data via I2C
+  \param[in]  addr        7b address [6:0] of I2C slave
+  \param[in]  numTx       number of bytes to send
+  \param[in]  bufTx       send buffer
+  \return error code (0=ok; 1=timeout)
+  write data to I2C slave with frame timeout. Note that no start or 
+  stop condition is generated.
+*/
+uint8_t i2c_send(uint8_t addr, uint8_t numTx, uint8_t *bufTx) {
+  uint8_t   i;
+
+  // send 7b slave adress [7:1] + write flag (LSB=0)
+  I2C->DR = (uint8_t) ((addr << 1) & ~0x01);       // shift left and set LSB (write=0, read=1)
+  I2C_timeout = 10;
+  while ((!(I2C->SR1 & I2C_SR1_ADDR)) && I2C_timeout);     // wait until address sent or timeout
+  I2C_timeout = 10;
+  while ((!(I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);     // seems to be required...???
+  
+  // no I2C timeout -> send data
+  if (I2C_timeout) {
+    for (i=0; i<numTx; i++) {
+      I2C->DR = bufTx[i];
+      I2C_timeout = 2;
+      while ((!(I2C->SR1 & I2C_SR1_TXE)) && I2C_timeout);  // wait until DR buffer empty or timeout
+    }
+  }
+  // on I2C timeout return error
+  else {
+    i2c_init();
+    return(1);
+  }
+
+  // return success
+  return(0);
+} // i2c_send
+
+static uint8_t i2c_read(void) {
+    I2C->CR2 &= ~I2C_CR2_ACK;
+    i2c_stop();
+    while (!(I2C->SR1 & I2C_SR1_RXNE));
+    return I2C->DR;
+}
+
+/**
+  \fn uint8_t i2c_request(uint8_t slaveAddr, uint8_t numRx, uint8_t *bufRx)
+  \brief request data via I2C as master with i2c_stop()
+  \param[in]  slaveAddr   7b address [6:0] of I2C slave
+  \param[in]  numRx       number of bytes to receive
+  \param[out] bufRx       receive buffer
+  \return error code (0=ok; 1=timeout)
+  request data from I2C slave with frame timeout. Note that no start or 
+  stop condition is generated.
+*/
+uint8_t i2c_request(const uint8_t slaveAddr, const uint8_t numRx, uint8_t *bufRx) {
+  uint8_t i = numRx;
+  
+  // send 7b slave adress [7:1] + read flag (LSB=1)
+  I2C->DR = (uint8_t) ((slaveAddr << 1) | 0x01);   // shift left and set LSB (write=0, read=1)
+  I2C_timeout = 10;
+  while ((!(I2C->SR1 & I2C_SR1_ADDR)) && I2C_timeout);   // wait until adress sent or timeout
+  I2C_timeout = 2;
+  while ((!(I2C->SR3 & I2C_SR3_BUSY)) && I2C_timeout);   // seems to be required...???
+
+  while (i-- > 1) {
+    I2C_timeout = 2;
+    while ((!(I2C->SR1 & I2C_SR1_RXNE)) && I2C_timeout); // wait until DR buffer not empty or timeout
+    *(bufRx++) = I2C->DR;
+  }
+    *bufRx = i2c_read();
+ 
+  // on I2C timeout return error
+  if (I2C_timeout == 0) {
+    i2c_init();
+    return(1);
+  }
+
+  // return success
+  return(0);
+} // i2c_request
+
+/*-----------------------------------------------------------------------------
+    END OF MODULE
+-----------------------------------------------------------------------------*/

+ 45 - 0
lib/i2c.h

@@ -0,0 +1,45 @@
+/**
+  \file i2c.h
+   
+  \author G. Icking-Konert
+  \date 2013-11-22
+  \version 0.1
+   
+  \brief declaration of I2C functions/macros
+   
+  declaration of functions for I2C bus communication
+  For I2C bus, see http://en.wikipedia.org/wiki/I2C
+*/
+
+/*-----------------------------------------------------------------------------
+    MODULE DEFINITION FOR MULTIPLE INCLUSION
+-----------------------------------------------------------------------------*/
+#ifndef _I2C_H_
+#define _I2C_H_
+
+/*-----------------------------------------------------------------------------
+    DECLARATION OF GLOBAL FUNCTIONS
+-----------------------------------------------------------------------------*/
+
+/// configure I2C bus as master in standard mode
+void      i2c_init(void);
+
+/// wait until bus is free
+uint8_t   i2c_waitFree(void);
+
+/// generate I2C start condition
+uint8_t   i2c_start(void);
+
+/// generate I2C stop condition
+uint8_t   i2c_stop(void);
+
+/// write data via I2C
+uint8_t   i2c_send(uint8_t addr, uint8_t numTx, uint8_t *Tx);
+
+/// request data via I2C as master
+uint8_t   i2c_request(uint8_t addr, uint8_t numRx, uint8_t *Rx);
+
+/*-----------------------------------------------------------------------------
+    END OF MODULE DEFINITION FOR MULTIPLE INLUSION
+-----------------------------------------------------------------------------*/
+#endif // _I2C_H_

+ 206 - 0
lib/sensor.c

@@ -0,0 +1,206 @@
+#include "stm8s.h"
+#include "sensor.h"
+#include "i2c.h"
+#include "delay.h"
+
+/* Defines */
+#define AHT_I2C_ADDR    0x38
+
+#define CMD_GET_STATUS  0x71
+#define CMD_INIT        0xbe
+#define CMD_MEASURE     0xac
+#define CMD_MEASURE_CTL 0x33
+#define CMD_MEASURE_NOP 0x00
+#define CMD_SRESET      0xba
+#define CMD_CALIBR1     0x1b
+#define CMD_CALIBR2     0x1c
+#define CMD_CALIBR3     0x1e
+
+#define STATUS_BUSY 0x80
+#define STATUS_CMD  0x40
+#define STATUS_CYC  0x20
+#define STATUS_CAL  0x08
+#define STATUS_CALB 0x18
+
+/* Functions prototypes */
+static uint8_t Calc_CRC8(uint8_t *message, uint8_t Num);
+static aht20_st_t JH_Reset_REG(uint8_t addr);
+
+/**
+ * Initialization
+ */
+aht20_st_t AHT20_Init(void)
+{
+  uint8_t buf[2];
+
+  // Just powered on, it takes time for the product chip to be ready internally,
+  // the delay is 100~500ms, and 500ms is recommended
+  Delay(500);
+
+  // When power on, send 0x71 to read the status word for the first time,
+  // and judge whether the status word is 0x18.
+  i2c_start();
+  buf[0] = CMD_GET_STATUS;
+  if (! i2c_send(AHT_I2C_ADDR, 1, buf)) {
+    return AHT_St_Err;
+  }
+
+  /* get one byte */
+  if (! i2c_request(AHT_I2C_ADDR, 1, buf)) {
+    return AHT_St_Err;
+  }
+
+  if ((buf[0] & STATUS_CALB) != STATUS_CALB) {
+    //reinitialize registers
+    aht20_st_t rest;
+    rest = JH_Reset_REG(0x1b);
+    if (rest != AHT_St_OK) {
+      return AHT_St_Err;
+    }
+    rest = JH_Reset_REG(0x1c);
+    if (rest != AHT_St_OK) {
+      return AHT_St_Err;
+    }
+    rest = JH_Reset_REG(0x1e);
+    if (rest != AHT_St_OK) {
+      return AHT_St_Err;
+    }
+
+    Delay(1);
+  }
+
+  return AHT_St_OK;
+}
+
+aht20_st_t AHT20_SoftReset(void)
+{
+  uint8_t buf[2];
+  i2c_start();
+
+  buf[0] = CMD_SRESET;
+  if (! i2c_send(AHT_I2C_ADDR, 1, buf)) {
+    return AHT_St_Err;
+  }
+  i2c_stop();
+
+  return AHT_St_OK;
+}
+
+aht20_st_t AHT20_StartMeasure(void)
+{
+  uint8_t buf[4];
+  i2c_start();
+
+  buf[0] = CMD_MEASURE;
+  buf[1] = CMD_MEASURE_CTL;
+  buf[2] = CMD_MEASURE_NOP;
+  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
+    return AHT_St_Err;
+  }
+  i2c_stop();
+
+  return AHT_St_OK;
+}
+
+aht20_st_t AHT20_GetData(aht20_t * data)
+{
+  i2c_start();
+
+  /* Now read 7 bytes of data */
+  uint8_t buf[8];
+  if (! i2c_request(AHT_I2C_ADDR, 7, buf)) {
+    return AHT_St_Err;
+  }
+
+  if ((buf[0] & STATUS_BUSY) != 0) {
+    return AHT_St_Bsy;
+  }
+
+  /* Calculate values */
+  uint32_t result;
+
+  /* Humidity = Srh * 100% / 2^20 */
+  result = buf[1];
+  result <<= 8;
+  result |= buf[2];
+  result <<= 8;
+  result |= buf[3];
+  result >>= 4;
+  result *= 1000;
+  result += 524288;
+  result /= 256;
+  result /= 256;
+  result /= 16;
+  data->Humidity = (uint16_t)result;
+
+  /* Temperature = St * 200 / 2^20 - 50 */
+  result = buf[3] & 0xf;
+  result <<= 8;
+  result |= buf[4];
+  result <<= 8;
+  result |= buf[5];
+  result *= 2000;
+  result += 524288;
+  result /= 256;
+  result /= 256;
+  result /= 16;
+  data->Temperature = (int16_t)(result - 500);
+
+  return AHT_St_OK;
+}
+
+/**
+ * CRC check type: CRC8/MAXIM
+ * Polynomial: X8+X5+X4+1
+ * Poly: 0011 0001 0x31
+ * When the high bit is placed in the back, it becomes 1000 1100 0x8c
+ */
+static uint8_t Calc_CRC8(uint8_t *message, uint8_t Num)
+{
+  uint8_t i;
+  uint8_t byte;
+  uint8_t crc = 0xFF;
+
+  for (byte=0; byte<Num; byte++) {
+    crc ^= (message[byte]);
+    for (i=8; i>0; --i) {
+      if (crc & 0x80) {
+        crc = (crc << 1) ^ 0x31;
+      } else {
+        crc = (crc << 1);
+      }
+    }
+  }
+
+  return crc;
+}
+
+/* Reset register */
+static aht20_st_t JH_Reset_REG(uint8_t addr) {
+  uint8_t buf[4];
+
+  i2c_start();
+  buf[0] = addr;
+  buf[1] = 0;
+  buf[2] = 0;
+  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
+    return AHT_St_Err;
+  }
+  i2c_stop();
+
+  Delay(5); //Delay about 5ms
+  i2c_start();
+  if (! i2c_request(AHT_I2C_ADDR, 3, buf)) {
+    return AHT_St_Err;
+  }
+
+  Delay(10); //Delay about 10ms
+  i2c_start();
+  buf[0] = (0xB0|addr);
+  if (! i2c_send(AHT_I2C_ADDR, 3, buf)) {
+    return AHT_St_Err;
+  }
+  i2c_stop();
+
+  return AHT_St_OK;
+}

+ 25 - 0
lib/sensor.h

@@ -0,0 +1,25 @@
+#pragma once
+#ifndef _SENSOR_H_
+#define _SENSOR_H_
+
+/* Status code */
+typedef enum {
+  AHT_St_OK = 0,
+  AHT_St_Err,
+  AHT_St_Bsy,
+  AHT_St_CRC
+} aht20_st_t;
+
+/* Data type */
+typedef struct {
+  uint16_t Humidity;
+   int16_t Temperature;
+} aht20_t;
+
+/* Function */
+aht20_st_t AHT20_Init(void);
+aht20_st_t AHT20_StartMeasure(void);
+aht20_st_t AHT20_SoftReset(void);
+aht20_st_t AHT20_GetData(aht20_t * data);
+
+#endif /* _SENSOR_H_ */

+ 16 - 21
src/main.c

@@ -21,10 +21,9 @@
 #include "stm8s.h"
 #include "board.h"
 #include "i2c.h"
-#include "i2c_master_poll.h"
 #include "led.h"
 #include "delay.h"
-#include "htu21.h"
+#include "sensor.h"
 
 /* Private define ------------------------------------------------------------*/
 #define TIM4_PERIOD  (uint8_t)124
@@ -34,8 +33,7 @@
 /* Private variables ---------------------------------------------------------*/
 __IO uint16_t ConversionBuffer[ADC_SMPLS];
 __IO uint8_t BufferIndex = 0;
-static int16_t Temperature;
-static uint16_t Humidity;
+static aht20_t Sensor;
 
 /* Private function prototypes -----------------------------------------------*/
 static void boardInit(void);
@@ -51,45 +49,37 @@ void main(void)
   LedDigits[7] = led_H;
 
   /* I2C Configuration */
-  //i2c_master_init();
-  I2C_Init();
-  uint8_t buf[3];
-  buf[0] = 0xfe;
-  i2c_wr_data(0x40, 1, buf);
-  Delay(20);
-  buf[0] = 0xe6;
-  buf[1] = 0x06;
-  i2c_wr_data(0x40, 1, buf);
-  Delay(20);
+  i2c_init();
+  AHT20_Init();
 
   /* Infinite loop */
   while (1) {
-    htu_GetTemperature(&Temperature);
+    AHT20_StartMeasure();
+    Delay(450);
+    AHT20_GetData(&Sensor);
     showT();
-    Delay(400);
-    htu_GetHumidity(&Humidity);
     showH();
-    Delay(400);
+    Delay(450);
   }
 
 }
 
 /* Private functions ---------------------------------------------------------*/
 static void showT(void) {
-  int16_t t = (Temperature + 5) / 10;
+  int16_t t = Sensor.Temperature;
   uint8_t a;
 
   if (t < 0) {
     t *= -1;
   }
-  LedDigits[0] = t / 100;
+  LedDigits[0] =  t / 100;
   a = t % 100;
   LedDigits[1] = a / 10;
   LedDigits[2] = a % 10;
 }
 
 static void showH(void) {
- uint16_t h = Humidity; //(Humidity + 5) / 10;
+ uint16_t h = Sensor.Humidity;
  uint8_t a;
 
  LedDigits[4] = h / 100;
@@ -138,6 +128,11 @@ static void boardInit(void) {
   SPI_PORT->CR1 |= (uint8_t)(SPI_SCK|SPI_DATA);
   SPI_PORT->CR2 |= (uint8_t)(SPI_SCK|SPI_DATA);
 
+  /* I2C GPIO SDA SCL - HiZ, Open drain, Fast */
+  GPIOB->DDR |= (GPIO_PIN_4 | GPIO_PIN_5);
+  GPIOB->ODR |= (GPIO_PIN_4 | GPIO_PIN_5);
+  GPIOB->CR2 |= (GPIO_PIN_4 | GPIO_PIN_5);
+
   /** Configure ADC */
   /* De-Init ADC peripheral*/
   //ADC1_DeInit();