[Jihai APM32F4xx Tiny] Jihai APM32F407__IIC_STH30 (2)
[Copy link]
This post was last edited by Yin Xiaozhou on 2023-7-7 11:43
Preface
In this post, we will introduce how to use the common IO port of APM32F407 to simulate IIC timing and realize communication with STH30. In this post, we will use the common IO port of APM32F407 to simulate IIC timing to realize the reading and writing of SHT30 registers, and read the temperature and humidity data collected by SHT30 and print it on the computer through the serial port. This article is divided into the following parts:
- SHT30 Introduction
- IIC Protocol Introduction
- Data printing software design
- Download Verification
SHT30 Introduction
SHT30 is a temperature and humidity sensor produced by the Swiss company Shengshi Ruien. From SHT10 to SHT31, Shengshi Ruien's sensors are quite good.
Utilizes I2C for data transmission, has two selectable addresses, and a wide power supply voltage from 2.4V to 5.5V.
SHT30 supports a maximum transmission rate of 1000k, so the communication time is very short.
There are two ways to read the value of sht30. I will introduce the status query and value query methods using iic.
Send command: 0xF32D.
Send command 0x2C06
In this mode, issuing a measurement command triggers the acquisition of a data pair. Each data pair consists of a 16-bit temperature and a 16-bit humidity value (in that order).
The data value is always followed by a CRC checksum during transmission.
After sending through iic, the value returned by sht30 is an array of 6 bytes.
1[high eight digits of temperature] 2[eighth digit of temperature] 3[temperature crc check]
4[humidity high eight digits] 5[humidity eighth digit] 6[humidity CRC check]
IIC Protocol Introduction
Physical layer characteristics:
- A bus that supports multiple devices (signal lines shared by multiple devices). In the I2C communication bus, multiple communication hosts and communication slaves can be connected.
- An I2C bus uses only two bus lines, a bidirectional serial data line (SDA) and a serial clock line (SCL). The data line is used to send data, and the clock line is used for data transmission and reception synchronization.
- Each device connected to the bus has an independent address (seven bits or ten bits), and the host accesses the slave device based on the device address.
- The bus needs to be connected to a pull-up resistor to the power supply. When the I2C bus is idle, the output is high-impedance. When all devices are idle, they all output high-impedance. The pull-up resistor pulls the bus to a high level.
- Three communication modes: Standard mode (up to 100KHz) Fast mode (up to 400KHz)
- Fast-mode Plus (up to 1MHz).
- When multiple hosts use the bus at the same time, data conflicts can be prevented by using bus arbitration to decide which device occupies the bus.
- Programmable setup and hold time, can program the high level time and low level time of SCL in I2C.
Protocol layer features:
- Data is sent in the form of frames, each frame consists of 1 byte (8 bits).
- During the rising edge of SCL, SDA needs to remain stable, and SDA changes during the low period of SCL.
- In addition to data frames, the I2C bus also has start signals, stop signals, and response signals.
- Start bit: When SCL is at a stable high level, a falling edge of SDA starts transmission.
- Stop bit: When SCL is at a stable high level, a rising edge of SDA stops sending.
- Acknowledge bit: used to indicate that a byte has been sent successfully. Bus transmitter (whether master or slave),
- After sending 8 bits of data, SDA will be released (changed from output to input). During the ninth clock pulse, the receiver pulls SDA low to acknowledge receipt of the data.
IIC communication process
(1) Gray: This data is sent from the host to the slave.
(2) S: start signal
(3) SLAVE ADDRESS: slave address
(4) White: This data is sent from the slave to the master
(5) R/W: Transmission direction selection bit 1 for reading 0 for writing
(6) P: Stop signal
Data printing software design
Software Delay
#include "apm32f4xx.h"
#include "SysTick_Delay.h"
/**@} end of group SysTick_TimeBase_Macros*/
static __IO u32 TimingDelay;
/*!
* @brief Start SysTick
*
* @param None
*
* @retval None
*/
void SysTick_Init(void)
{
/** SystemFrequency / 1000 = 1ms */
if (SysTick_Config(SystemCoreClock / 1000))
{
/** Capture error */
while (1);
}
}
/*!
* @brief Precise Delay
*
* @param nTime in milliseconds
*
* @retval None
*/
void SysTick_Delay_ms(__IO u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
/*!
* @brief Precise Delay
*
* @param nTime in milliseconds
*
* @retval None
*/
void SysTick_Delay_us(__IO u32 nTime)
{
SysTick_Config(SystemCoreClock / 1000000);
TimingDelay = nTime;
while(TimingDelay != 0);
SysTick_Config(SystemCoreClock / 1000);
}
/*!
* @brief Decrements the TimingDelay
*
* @param None
*
* @retval None
*/
void TimingDelay_Decrement(void)
{
if(TimingDelay != 0)
{
TimingDelay--;
}
}
SysTick_Config (SystemCoreClock/1000); This function turns on the SysTick interrupt and also sets the Systick reload register. SystemCoreClock/1000 is one thousandth of the system clock frequency. That is, every second, the Systick register will be reloaded 1000 times, 1ms each time. If the SystemCoreClock / 1000000每次就是1us,1us Systick interrupt is too frequent, it will be restored after a delay of 1ms.
GPIO emulation IIC
#ifndef __I2C_H
#define __I2C_H
#include "apm32f4xx.h"
#include "SysTick_Delay.h"
#include "apm32f4xx_gpio.h"
#include "apm32f4xx_rcm.h"
/**********************
引脚别名定义
***********************/
#define I2C_PageSize 8
#define I2C_SCL_GPIO_PIN GPIO_PIN_6
#define I2C_SCL_GPIO_PORT GPIOB
#define I2C_SCL_GPIO_CLK RCM_AHB1_PERIPH_GPIOB
#define I2C_SCL_SOURCE GPIO_PIN_SOURCE_6
#define I2C_SDA_GPIO_PIN GPIO_PIN_7
#define I2C_SDA_GPIO_PORT GPIOB
#define I2C_SDA_GPIO_CLK RCM_AHB1_PERIPH_GPIOB
#define I2C_SDA_SOURCE GPIO_PIN_SOURCE_7
#define I2C_SDA_IN() { I2C_SDA_GPIO_PORT->MODE &= ~(7 << (3 * 2)); I2C_SDA_GPIO_PORT->MODE |= 0 << 7 * 2; }
#define I2C_SDA_OUT() { I2C_SDA_GPIO_PORT->MODE &= ~(7 << (3 * 2)); I2C_SDA_GPIO_PORT->MODE |= 1 << 7 * 2; }
#define I2C_SCL_1 GPIO_SetBit(I2C_SCL_GPIO_PORT,I2C_SCL_GPIO_PIN)
#define I2C_SCL_0 GPIO_ResetBit(I2C_SCL_GPIO_PORT,I2C_SCL_GPIO_PIN)
#define I2C_SDA_1 GPIO_SetBit(I2C_SDA_GPIO_PORT,I2C_SDA_GPIO_PIN)
#define I2C_SDA_0 GPIO_ResetBit(I2C_SDA_GPIO_PORT,I2C_SDA_GPIO_PIN)
#define I2C_SDA_INPUT GPIO_ReadInputBit(I2C_SDA_GPIO_PORT,I2C_SDA_GPIO_PIN)
/* Private function prototypes -----------------------------------------------*/
void GPIO_Simulation_IIC_Config(void);
void I2C_delay(void);
unsigned char I2C_Start(void);
void I2C_Stop(void);
void I2C_Ack(void);
void I2C_NoAck(void);
unsigned char I2C_WaitAck(void) ;
void I2C_SendByte(unsigned char SendByte) ;
unsigned char I2C_ReceiveByte(void) ;
#endif
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
//头文件
#include "i2c.h"
void GPIO_Simulation_IIC_Config(void)
{
GPIO_Config_T gpioConfigStruct;
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOB);
gpioConfigStruct.pin = GPIO_PIN_6|GPIO_PIN_7;
gpioConfigStruct.mode = GPIO_MODE_OUT;
gpioConfigStruct.speed = GPIO_SPEED_50MHz;
gpioConfigStruct.otype = GPIO_OTYPE_OD;
gpioConfigStruct.pupd = GPIO_PUPD_NOPULL;
GPIO_Config(GPIOB, &gpioConfigStruct);
I2C_SCL_1;
I2C_SDA_1;
}
/**
* @File I2C_delay
* @brief 延迟时间
* @param 无
* @retval 无
*/
void I2C_delay(void) //for 1T STC delay
{
SysTick_Delay_us(5);
}
/**
* @file I2C_Start
* @brief 起始信号
* @param 无
* @retval 无
*/
unsigned char I2C_Start(void)
{
I2C_SDA_1;
I2C_SCL_1;
I2C_delay();
I2C_SDA_IN();
if(!I2C_SDA_INPUT)return 0; /* SDA线为低电平则总线忙,退出 */
I2C_SDA_OUT();
I2C_SDA_0;
I2C_delay();
I2C_SDA_IN();
if(I2C_SDA_INPUT) return 0; /* SDA线为高电平则总线出错,退出 */
I2C_SDA_OUT();
I2C_SDA_0;
I2C_delay();
return 1;
}
/**
* @file I2C_Stop
* @brief 停止信号
* @param 无
* @retval 无
*/
void I2C_Stop(void)
{
I2C_SCL_0;
I2C_delay();
I2C_SDA_0;
I2C_delay();
I2C_SCL_1;
I2C_delay();
I2C_SDA_1;
I2C_delay();
}
/**
* @file I2C_Ack
* @brief 应答信号
* @param 无
* @retval 无
*/
void I2C_Ack(void)
{
I2C_SCL_0;
I2C_delay();
I2C_SDA_0;
I2C_delay();
I2C_SCL_1;
I2C_delay();
I2C_SCL_0;
I2C_delay();
}
/**
* @file I2C_NoAck
* @brief 无应答信号
* @param 无
* @retval 无
*/
void I2C_NoAck(void)
{
I2C_SCL_0;
I2C_delay();
I2C_SDA_1;
I2C_delay();
I2C_SCL_1;
I2C_delay();
I2C_SCL_0;
I2C_delay();
}
/**
* @file I2C_WaitAck
* @brief 等待Ack
* @param 无
* @retval 返回为:=1有ACK,=0无ACK
*/
unsigned char I2C_WaitAck(void)
{
I2C_SCL_0;
I2C_delay();
I2C_SDA_1;
I2C_delay();
I2C_SCL_1;
I2C_delay();
I2C_SDA_IN();
if(I2C_SDA_INPUT)
{
I2C_SCL_0;
return 0;
}
I2C_SDA_OUT();
I2C_SCL_0;
return 1;
}
/**
* @file I2C_SendByte
* @brief 数据从高位到低位
* @param - SendByte: 发送的数据
* @retval 无
*/
void I2C_SendByte(unsigned char SendByte)
{
unsigned char i=8;
while(i--)
{
I2C_SCL_0;
I2C_delay();
if(SendByte&0x80)
I2C_SDA_1;
else
I2C_SDA_0;
SendByte<<=1;
I2C_delay();
I2C_SCL_1;
I2C_delay();
}
I2C_SCL_0;
}
/**
* @file I2C_ReceiveByte
* @brief 数据从高位到低位
* @param 无
* @retval I2C总线返回的数据
*/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i=8;
unsigned char ReceiveByte=0;
I2C_SDA_1;
I2C_SDA_IN();
while(i--)
{
ReceiveByte<<=1;
I2C_SCL_0;
I2C_delay();
I2C_SCL_1;
I2C_delay();
if(I2C_SDA_INPUT)
{
ReceiveByte|=0x01;
}
}
I2C_SDA_OUT();
I2C_SCL_0;
return ReceiveByte;
}
/*********************************************************************************************************
END FILE
*********************************************************************************************************/
Main function implementation
/*!
* @file main.c
*
* @brief Main program body
*
* @version V1.0.2
*
* @date 2023-03-01
*
* @attention
*
* Copyright (C) 2021-2023 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
*
* The program is only for reference, which is distributed in the hope
* that it will be useful and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
* and limitations under the License.
*/
/* Includes */
#include "main.h"
#include "Board.h"
#include "SysTick_Delay.h"
#include "stdio.h"
#include "stdarg.h"
#include "SHT30.h"
/* printf function configs to USART1*/
#define DEBUG_USART USART1
#define LED2(x) GPIO_WriteBitValue(GPIOE, GPIO_PIN_5,x)
#define LED3(x) GPIO_WriteBitValue(GPIOE, GPIO_PIN_6,x)
#define KEY1 GPIO_ReadInputBit(GPIOC,GPIO_PIN_10)
#define KEY2 GPIO_ReadInputBit(GPIOC,GPIO_PIN_11)
USART_Config_T usartConfigStruct; //串口配置结构体
void LED_GPIO_Config(void)
{
GPIO_Config_T configStruct;
/** 开启GPIO_LED时钟 */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOE);
/** 配置GPIO_LED引脚 */
GPIO_ConfigStructInit(&configStruct);
configStruct.pin = GPIO_PIN_5; //不支持或
configStruct.mode = GPIO_MODE_OUT;
configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOE, &configStruct);
configStruct.pin = GPIO_PIN_6; //不支持或
GPIO_Config(GPIOE, &configStruct);
//设置GPIO为低电平,不点亮LED
GPIO_SetBit(GPIOE, GPIO_PIN_5);
GPIO_SetBit(GPIOE, GPIO_PIN_6);
}
void KEY_GPIO_Config(void)
{
GPIO_Config_T configStruct;
/** 开启GPIO_LED时钟 */
RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOC);
/** 配置GPIO_LED引脚 */
GPIO_ConfigStructInit(&configStruct);
configStruct.pin = GPIO_PIN_10; //不支持或
configStruct.mode = GPIO_MODE_IN;
configStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config(GPIOC, &configStruct);
configStruct.pin = GPIO_PIN_11; //不支持或
GPIO_Config(GPIOC, &configStruct);
}
void UART_init_Config(void)
{
/* USART configuration */
USART_ConfigStructInit(&usartConfigStruct);
usartConfigStruct.baudRate = 115200;
usartConfigStruct.mode = USART_MODE_TX_RX;
usartConfigStruct.parity = USART_PARITY_NONE;
usartConfigStruct.stopBits = USART_STOP_BIT_1;
usartConfigStruct.wordLength = USART_WORD_LEN_8B;
usartConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
/* COM1 init*/
APM_MINI_COMInit(COM1, &usartConfigStruct);
}
/*!
* @brief Main program
*
* @param None
*
* @retval None
*/
void Delay(void)
{
volatile uint32_t delay = 0x2FFFFF;
while (delay--);
}
/*!
* @brief USART write
*
* @param dat: data
*
* @param len: Data length
*
* @retval None
*/
void USART_Write(uint8_t* dat, uint8_t len)
{
uint8_t i;
for (i = 0; i < len; i++)
{
while (USART_ReadStatusFlag(USART1, USART_FLAG_TXBE) == RESET);
USART_TxData(USART1, dat[i]);
}
}
//void KEY_Input(void)
//{
// LED2(KEY1);
// LED3(KEY2);
//}
unsigned char key_read(void)
{
static unsigned char key_up = 1;
if(key_up &&( (KEY1 == BIT_RESET) || (KEY2 == BIT_RESET) ) )
{
SysTick_Delay_ms(10);
key_up = 0;
if(KEY1 == BIT_RESET) return 1;
else if(KEY2 == BIT_RESET) return 2;
}
if(KEY1&&KEY2) key_up = 1;
return 0;
}
/*!
* @brief Main program
*
* @param None
*
* @retval None
*/
int main(void)
{
unsigned char key = 0;
LED_GPIO_Config();
KEY_GPIO_Config();
SysTick_Init();
UART_init_Config();
SHT3X_Init();
printf("MCU init OK!\r\n");
while (1)
{
key = key_read();
switch (key)
{
case 1 :
LED2(0);
SysTick_Delay_ms(100);
SHT3X_TEST();
LED2(1);
break;
case 2 :
LED3(0);
SysTick_Delay_ms(100);
LED3(1);
break;
// KEY_Input();
}
}
}
/*!
* @brief Redirect C Library function printf to serial port.
* After Redirection, you can use printf function.
*
* @param ch: The characters that need to be send.
*
* @param *f: pointer to a FILE that can recording all information
* needed to control a stream
*
* @retval The characters that need to be send.
*
* @note
*/
int fputc(int ch, FILE* f)
{
/* send a byte of data to the serial port */
USART_TxData(DEBUG_USART, (uint8_t)ch);
/* wait for the data to be send */
while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);
return (ch);
}
Download Verification
Press a button and the data will be printed.
|