AIP650 I2C通讯
/**
* @file aip650.c
*
* @date 2020-5-19
*
* @author aron566
*
* @copyright None
*
* @brief AIP650 I2C通讯
*
* @details None
*
* @version V1.1
*/
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Includes -----------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
#include "aip650.h"
/** Private typedef ----------------------------------------------------------*/
/** Private macros -----------------------------------------------------------*/
/** Private constants --------------------------------------------------------*/
/** Public variables ---------------------------------------------------------*/
Key_Value_Save_t Key_Value_History =
{
.Key_value_ptr = NULL ,
.write_index = 0,
.read_index = 0,
.left_lenth = 0
};
uint8_t Key_Value_Arr[KEY_VALUE_BUF_MAX] = {
0};
/** Private variables --------------------------------------------------------*/
/** Private function prototypes ----------------------------------------------*/
static void Key_value_circle_init(void);
static int CQ_Putdata(uint8_t data);
static void delay_xus(__IO uint32_t nTime);
static void SDA_Output(void);
static void SDA_Input(void);
static void SCL_Output(void);
static void SCL_Input(void);
static void I2C_Init(void);
static void I2C_Start(void);
static void I2C_Stop(void);
static uint8_t I2C_Wait_Ack(void);
static void I2C_Ack(void);
static void I2C_NAck(void);
static void I2C_Send_Byte(uint8_t txd);
static uint8_t I2C_Read_Byte(uint8_t ack);
/** Private user code --------------------------------------------------------*/
/** Private application code -------------------------------------------------*/
/*******************************************************************************
*
* Static code
*
********************************************************************************
*/
/**
******************************************************************
* @brief 模拟I2C us级延时
* @param [in]nTime 延时us数
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void delay_xus(__IO uint32_t nTime)
{
int old_val,new_val,val;
if(nTime > 900)
{
for(old_val = 0; old_val < nTime/900; old_val++)
{
delay_xus(900);
}
nTime = nTime%900;
}
old_val = SysTick->VAL;
new_val = old_val - CPU_FREQUENCY_MHZ*nTime;
if(new_val >= 0)
{
do
{
val = SysTick->VAL;
}
while((val < old_val)&&(val >= new_val));
}
else
{
new_val +=CPU_FREQUENCY_MHZ*1000;
do
{
val = SysTick->VAL;
}
while((val <= old_val)||(val > new_val));
}
}
/**
******************************************************************
* @brief 模拟I2C 数据脚配置为输出模式
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void SDA_Output(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = MYI2C_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;/*GD32输出*/
GPIO_InitStruct.OutMode = GPIO_OTYPE_PP;/*GD32推挽输出*/
GPIO_InitStruct.Speed =GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MYI2C_SDA_PORT,&GPIO_InitStruct);
}
/**
******************************************************************
* @brief 模拟I2C 数据脚配置为输入模式
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void SDA_Input(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = MYI2C_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;/*没有上下拉*/
GPIO_InitStruct.Speed =GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MYI2C_SDA_PORT,&GPIO_InitStruct);
}
/**
******************************************************************
* @brief 模拟I2C 时钟脚配置为输出模式
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void SCL_Output(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = MYI2C_SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT;/*GD32输出*/
GPIO_InitStruct.OutMode = GPIO_OTYPE_PP;/*GD32推挽输出*/
GPIO_InitStruct.Speed =GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MYI2C_SCL_PORT,&GPIO_InitStruct);
}
/**
******************************************************************
* @brief 模拟I2C 时钟脚配置为输入模式
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void SCL_Input(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = MYI2C_SCL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;/*没有上下拉*/
GPIO_InitStruct.Speed =GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(MYI2C_SCL_PORT,&GPIO_InitStruct);
}
/**
******************************************************************
* @brief 模拟I2C初始化
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_Init(void)
{
SCL_Output();
SDA_Output();
SCL_Dout_HIGH();
SDA_Dout_HIGH();
}
/**
******************************************************************
* @brief 模拟I2C发出起始信号
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_Start(void)
{
SDA_Output();
SDA_Dout_HIGH();
SCL_Dout_HIGH();
Delay_us(4);
SDA_Dout_LOW();
Delay_us(4);
SCL_Dout_LOW();
}
/**
******************************************************************
* @brief 模拟I2C发出停止信号
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_Stop(void)
{
SDA_Output();
SCL_Dout_LOW();
SDA_Dout_LOW();
Delay_us(4);
SCL_Dout_HIGH();
SDA_Dout_HIGH();
Delay_us(4);
}
/**
******************************************************************
* @brief 模拟I2C等待应答
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static uint8_t I2C_Wait_Ack(void)
{
uint8_t ucErrTime=0;
SDA_Input();
SDA_Dout_HIGH();Delay_us(1);
SCL_Dout_HIGH();Delay_us(1);
while(SDA_Data_IN())
{
ucErrTime++;
if(ucErrTime>250)
{
I2C_Stop();
return 0;
}
}
SCL_Dout_LOW();//时钟输出0
return 0;
}
/**
******************************************************************
* @brief 模拟I2C应答
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_Ack(void)
{
SCL_Dout_LOW();
SDA_Output();
SDA_Dout_LOW();
Delay_us(2);
SCL_Dout_HIGH();
Delay_us(2);
SCL_Dout_LOW();
}
/**
******************************************************************
* @brief 模拟I2C不应答
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_NAck(void)
{
SCL_Dout_LOW();
SDA_Output();
SDA_Dout_HIGH();
Delay_us(2);
SCL_Dout_HIGH();
Delay_us(2);
SCL_Dout_LOW();
}
/**
******************************************************************
* @brief 模拟I2C发送一个字节
* @param [in]txd 发送的字节
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void I2C_Send_Byte(uint8_t txd)
{
uint8_t t;
//拉低时钟开始数据传输
SDA_Output();
SCL_Dout_LOW();
for(t=0;t<8;t++)
{
SDA_Write((txd&0x80)>>7);
txd<<=1;
Delay_us(5);
SCL_Dout_HIGH();
Delay_us(5);
SCL_Dout_LOW();
//Delay_us(2);
}
}
/**
******************************************************************
* @brief 模拟I2C读取一个字节
* @param [in]ack ack=1时,发送ACK,ack=0,发送nACK
* @retval 读取到的字节
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static uint8_t I2C_Read_Byte(uint8_t ack)
{
unsigned char i,receive=0;
//SDA设置为输入
SDA_Input();
for(i=0;i<8;i++ )
{
SCL_Dout_LOW();
Delay_us(5);
SCL_Dout_HIGH();
receive<<=1;
if(SDA_Data_IN())receive++;
Delay_us(5);
}
if(!ack)I2C_NAck();/**< 发送nACK*/
else I2C_Ack(); /**< 发送ACK*/
return receive;
}
/**
******************************************************************
* @brief 加入数据到环形缓冲区
* @param [in]data 一个字节数据
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static int CQ_Putdata(uint8_t data)
{
if(Key_Value_History.left_lenth < KEY_VALUE_BUF_MAX)
{
Key_Value_History.Key_value_ptr[Key_Value_History.write_index] = data;//存入缓存
Key_Value_History.write_index = (Key_Value_History.write_index + 1) % KEY_VALUE_BUF_MAX;//偏移下次存入地址
Key_Value_History.left_lenth++;//未读数据++
return 0;
}
return -1;
}
/**
******************************************************************
* @brief 按键键值环形缓冲区初始化
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
static void Key_value_circle_init(void)
{
Key_Value_History.Key_value_ptr = Key_Value_Arr;
Key_Value_History.read_index = 0;
Key_Value_History.write_index = 0;
}
/** Public application code --------------------------------------------------*/
/*******************************************************************************
*
* Public code
*
********************************************************************************
*/
/**
******************************************************************
* @brief 初始化AIP650 默认关断所有指示灯
* @param [in]None
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
void AIP_650_Init_Opt(void)
{
I2C_Init();//i2c初始化
Key_value_circle_init();//!< 键值缓冲区初始化
I2C_Start();
I2C_Send_Byte(0x48);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x00);
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x48);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x01);
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x68);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x00);
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x6A);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x00);
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x6C);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x00);
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x6E);
while(I2C_Wait_Ack());
I2C_Send_Byte(0x00);
while(I2C_Wait_Ack());
I2C_Stop();
}
/**
******************************************************************
* @brief 读取AIP650按键键值,并加入到环形缓冲区
* @param [in]None
* @retval 按键键值
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
uint8_t Read_Aip650_Key_Value(void)
{
static uint8_t ret = 0;
uint8_t Current_key_act = 0;
I2C_Start();
I2C_Send_Byte(0x4F);
while(I2C_Wait_Ack());
Current_key_act = I2C_Read_Byte(0);
I2C_Stop();
switch(Current_key_act)
{
case 0x45://S1
case 0x4D://S2
case 0x55://S3
case 0x5D://S4
case 0x65://S5
case 0x6D://S6
case 0x75://S7
case 0xFF://S8
case 0x47://S9
case 0x4F://S10
case 0x57://S11
case 0x5F://S12
ret = Current_key_act;
break;
default :
if(ret)
{
//按键松开,才判定一个按键产生
CQ_Putdata(ret);
ret = 0;
}
return 0;
}
return ret;
}
/**
******************************************************************
* @brief 从环形缓冲区取出数据
* @param [in]None
* @retval 一个字节数据
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
uint8_t CQ_Getdata(void)
{
uint8_t ret_data = 0;
if(Key_Value_History.left_lenth > 0)
{
ret_data = Key_Value_History.Key_value_ptr[Key_Value_History.read_index];//!< 读取数据
Key_Value_History.read_index = (Key_Value_History.read_index+1 >= KEY_VALUE_BUF_MAX ? 0 : Key_Value_History.read_index+1);//!< 地址偏移
Key_Value_History.left_lenth--;//!< 未读数据--
return ret_data;
}
return 0;
}
/**
******************************************************************
* @brief 设置LED值
* @param [in]command 0-7bit 控制HL1-HL8 8-15bit 控制HL9-HL10
* @retval None
* @author aron566
* @version V1.0
* @date 2020-5-18
******************************************************************
*/
void Set_LED_ON_OFF(uint32_t command)
{
I2C_Start();
I2C_Send_Byte(0x68);
while(I2C_Wait_Ack());
I2C_Send_Byte(command&0xFF); //!< 0-7 控制HL1-HL8
while(I2C_Wait_Ack());
I2C_Stop();
I2C_Start();
I2C_Send_Byte(0x6C);
while(I2C_Wait_Ack());
I2C_Send_Byte((command>>8)&0x03);//!< 8-15 控制HL9-HL10
while(I2C_Wait_Ack());
I2C_Stop();
}
#ifdef __cplusplus ///<end extern c
}
#endif
/**
* @file aip650.h
*
* @date 2020-5-19
*
* @author aron566
*
* @brief AIP650 I2C通讯
*
* @version V1.1
*/
#ifndef __MYI2C_H__
#define __MYI2C_H__
#ifdef __cplusplus ///<use C compiler
extern "C" {
#endif
/** Includes -----------------------------------------------------------------*/
#include <stdint.h> /**< nedd definition of uint8_t */
#include <stddef.h> /**< need definition of NULL */
//#include <stdbool.h>/**< need definition of BOOL */
#include <stdio.h> /**< if need printf */
#include <stdlib.h>
#include <string.h>
/** Private includes ---------------------------------------------------------*/
#include "main.h"
/** Private defines ----------------------------------------------------------*/
/**
* @name CPU频率
* @{
*/
#define CPU_FREQUENCY_MHZ 200
/** @}*/
/**
* @name 模拟I2C引脚定义,及配置功能
* @{
*/
#define MYI2C_SCL_PIN AIP_SCL_Pin
#define MYI2C_SCL_PORT AIP_SCL_GPIO_Port
#define MYI2C_SDA_PIN AIP_SDA_Pin
#define MYI2C_SDA_PORT AIP_SDA_GPIO_Port
/** @}*/
//按键缓存大小
#define KEY_VALUE_BUF_MAX 5U
/** Exported typedefines -----------------------------------------------------*/
/** 键值环形缓冲区*/
typedef struct Key_Value_Save
{
uint8_t *Key_value_ptr;
uint8_t write_index;
uint8_t read_index;
uint8_t left_lenth;
}Key_Value_Save_t;
/** Exported constants -------------------------------------------------------*/
/** Exported macros-----------------------------------------------------------*/
#define Delay_us(xx) delay_xus(xx)
#define SDA_Dout_LOW() HAL_GPIO_WritePin(MYI2C_SDA_PORT,MYI2C_SDA_PIN,GPIO_PIN_RESET)
#define SDA_Dout_HIGH() HAL_GPIO_WritePin(MYI2C_SDA_PORT,MYI2C_SDA_PIN,GPIO_PIN_SET)
#define SDA_Data_IN() HAL_GPIO_ReadPin(MYI2C_SDA_PORT,MYI2C_SDA_PIN)
#define SCL_Dout_LOW() HAL_GPIO_WritePin(MYI2C_SCL_PORT,MYI2C_SCL_PIN,GPIO_PIN_RESET)
#define SCL_Dout_HIGH() HAL_GPIO_WritePin(MYI2C_SCL_PORT,MYI2C_SCL_PIN,GPIO_PIN_SET)
#define SCL_Data_IN() HAL_GPIO_ReadPin(MYI2C_SCL_PORT,MYI2C_SCL_PIN)
#define SDA_Write(XX) HAL_GPIO_WritePin(MYI2C_SDA_PORT,MYI2C_SDA_PIN,(XX?GPIO_PIN_SET:GPIO_PIN_RESET))
/** Exported variables -------------------------------------------------------*/
extern Key_Value_Save_t Key_Value_History;
extern uint8_t Key_Value_Arr[];
/** Exported functions prototypes --------------------------------------------*/
void AIP_650_Init_Opt(void);
uint8_t Read_Aip650_Key_Value(void);
uint8_t CQ_Getdata(void);
void Set_LED_ON_OFF(uint32_t command);
#ifdef __cplusplus ///<end extern c
}
#endif
#endif
/******************************** End of file *********************************/