前言
本贴我们将向大家介绍如何利用 APM32F407的普通 IO 口模拟 IIC 时序,并实现和 STH30之 间的通信。在本贴中,我们将利用 APM32F407的普通 IO 口模拟 IIC 时序,来实现 SHT30的 寄存器的读写,并将读取SHT30采集到的温湿度数据,通过串口打印到在 电脑上。本文分为如下几个部分:
SHT30介绍
sht30是一个瑞士企业盛世瑞恩生产的温湿度传感器,从sht10到sht31,盛世瑞恩的传感器还是不错了。
利用I2C进行数据传输,具有两个可选地址,宽电源电压从2.4V到5.5V。
sht30最高支持1000k的传输速率。因此通讯时间非常短。
sht30有两种读取数值的方法,我介绍一下使用iic的状态查询和数值查询方法。
发送指令0x2C06
在这种模式下,发出测量命令触发一个数据对的获取。每个数据对由一个16位温度和一个16位组成湿度值(按此顺序)。
在传输过程中data值后面总是跟一个CRC校验和。
通过iic发送完毕之后,sht30返回的数值是6个字节的数组。
1[温度高八位] 2[温度第八位] 3[温度crc校验]
4[湿度高八位] 5[湿度第八位] 6[湿度crc校验]
IIC协议介绍
物理层特点:
协议层特点:
IIC通讯过程
(1) 灰色此数据由主机发送到从机
(2) S:起始信号
(3) SLAVE ADDRESS:从机地址
(4) 白色此数据由从机发送到主机
(5) R/W :发送方向选择位 1 为读取 0 为写入
(6) P:停止信号
数据打印软件设计
软件延时
#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) ; 这个函数打开了SysTick的中断,同时也设置了Systick的重装载寄存器。 SystemCoreClock/1000既是系通时钟频率的千分之一。 也就是说没每秒钟,Systick寄存器会装满1000次,每次1ms,SystemCoreClock / 1000000每次就是1us,1us
Systick中断太频烦延时之后恢复1ms.
GPIO模拟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
*********************************************************************************************************/
主函数实现
/*!
* @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);
}
下载验证
按一下按键,就会打印下数据
本帖最后由 尹小舟 于 2023-7-7 11:43 编辑