IIC类型:
⑴模拟IIC
⑵硬件IIC
ACK:确认字符ACK (Acknowledge character)即是确认字符,在数据通信中,接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。在TCP/IP协议中,如果接收方成功的接收到数据,那么会回复一个ACK数据。通常ACK信号有自己固定的格式,长度大小,由接收方回复给发送方。
NACK:否认字符NACK(Negative Acknowledge) 含义为接收站对所收到的报文进行检查,若发现错误,便向发送站发送否认回答NAK,表示报文有错,并要求重发。
SYN:同步字符SYN( Synchronousidle)表示无论是中心结点还是远地结点,在发送信息或回答之前,都要先发送同步字符,用以实现或保持发送站和接收站之间的同步。
DLE:转义字符DLE( Data Link Escape)用于改变紧随其后的有限个字符的意义,以提供附加的数据链路控制字符。
IIC总线:IIC一共有两条总线,一条是SDA(Serial Data)数据总线,用来传输数据的;一条是SCL(Serial clock line)时钟线,用来控制发送数据时序的。总线不忙时,数据线和时钟线保持高电平。
BM8563 IIC起始信号:时钟线为高电平时,数据线出现一个下降沿为起始信号。注意:最后时钟线要拉低
BM8563 IIC终止信号:时钟线为高电平时,数据线出现一个上升沿为终止信号。
BM8563 IIC数据位传送:每个时钟信号(即SCL总线的由一个高电平跳变为低电平的周期信号)传送一个数据位;在SCL时钟线低电平时才允许SDA数据线改变,SCL时钟线高电平时SDA数据线应该保持稳定,否则SDA数据线上的数据会变成起始、终止信号。
BM8563 IIC应答位:每8个字节后,后面会有一个应答位。主设备写操作时,写完8位字节后需要读取从设备发过来的应答;主设备读操作时,读完8位字节后需要给给从设备主动发送一个应答。
BM8563从地址:前面七位为从设备地址,第八位为读写操作位。即写操作为0xA2,读操作为0xA3。
BM8563 写时序:⑴IIC Start起始信号
⑵IIC Write从地址0xA2
⑶读取从器件应答信号
⑷IIC Write字地址(寄存器地址)
⑸读取从器件应答信号
⑹IIC Write数据
⑺读取从器件应答信号
⑻IIC Stop终止信号
注意:如果需要一次性写进去,利用数组重复⑹⑺操作即可。
自动增量寄存器字地址:第一个操作的寄存器是所写的寄存器字地址所对应的寄存器,重复⑹⑺下一个操作的的寄存器为所写字地址+1。
BM8563 读时序:⑴IIC Start起始信号
⑵IIC Write从地址0xA2
⑶读取从器件应答信号
⑷IIC Write字地址(寄存器地址)
⑸读取从器件应答信号
⑹IIC Start起始信号
⑺IIC Write从地址0xA3
⑻读取从器件应答信号
⑼IIC Read数据
⑽给从设备发送应答信号
⑾IIC Stop终止信号
注意:如果需要一次性读出来,利用数组存重复⑹⑺操作即可。
寄存器地址:
#ifndef _IIC_H_
#define _IIC_H_
#define EEPROM_I2C_WR 0 /* 写控制bit */
#define EEPROM_I2C_RD 1 /* 读控制bit */
#define EEPROM_DEV_ADDR 0xA0 /* 24xx02的设备地址 */
#define EEPROM_PAGE_SIZE 8 /* 24xx02的页面大小 */
#define EEPROM_SIZE 256 /* 24xx02总容量 */
#define IIC_SCL_SET() GPIO_SetOutBits(HT_GPIOA, GPIO_PIN_0)
#define IIC_SCL_RESET() GPIO_ClearOutBits(HT_GPIOA, GPIO_PIN_0)
#define IIC_SDA_SET() GPIO_SetOutBits(HT_GPIOA, GPIO_PIN_1)
#define IIC_SDA_RESET() GPIO_ClearOutBits(HT_GPIOA, GPIO_PIN_1)
void IIC_Init(void);
void Systick_Delay_ms(u32 ms);
void Systick_Delay_us(u32 us);
void IIC_Start(void);
void IIC_Stop(void);
uint8_t IN_SDA(void);
void IIC_RTC_SDA_IN(void);
void IIC_RTC_SDA_OUT(void);
void IIC_Ack(uint8_t a);
void IIC_Write_Byte(uint8_t data);
uint8_t IIC_Read_Byte(void);
void BM8563_Write_Byte(void);
void BM8563_Read_Byte(void);
uint8_t BM8563_Write(uint8_t sla,uint8_t suba,uint8_t data);
uint8_t BM8563_Read(uint8_t sla,uint8_t suba);
uint8_t BM8563_Read_data(uint8_t sla,uint8_t suba,uint8_t *s, uint8_t length);
void BM8563_Write_Byte(void);
void BM8563_Init(void);
#endif
#include "ht32.h"
#include "ht32_board.h"
#include "iic.h"
#include "usart.h"
uint8_t ReadData[7] = {0};
volatile uint8_t ack = 0;
volatile uint8_t bm_status = 0;//如果BM时钟芯片无应答,则为0,。应答正常则为1.
void IIC_Init(void)
{
CKCU_PeripClockConfig_TypeDef CCLOCK;
CCLOCK.Bit.PA = 1;
CCLOCK.Bit.AFIO = 1;
CKCU_PeripClockConfig(CCLOCK, ENABLE);
AFIO_GPxConfig(GPIO_PA, GPIO_PIN_0, AFIO_FUN_GPIO);
AFIO_GPxConfig(GPIO_PA, GPIO_PIN_1, AFIO_FUN_GPIO);
/* Configure the GPIO pin */
//GPIO_PullResistorConfig(HT_GPIOA, GPIO_PIN_0, GPIO_PR_DISABLE);
//GPIO_DriveConfig(HT_GPIOA, GPIO_PIN_0, GPIO_DV_8MA);
GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_0, GPIO_DIR_OUT);
// GPIO_PullResistorConfig(HT_GPIOA, GPIO_PIN_1, GPIO_PR_DISABLE);
// GPIO_DriveConfig(HT_GPIOA, GPIO_PIN_1, GPIO_DV_8MA);
GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_1, GPIO_DIR_OUT);
IIC_Stop();
}
void IIC_RTC_SDA_IN(void)
{
GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_1, GPIO_DIR_IN);
GPIO_InputConfig(HT_GPIOA, GPIO_PIN_1, ENABLE);
}
void IIC_RTC_SDA_OUT(void)
{
GPIO_DirectionConfig(HT_GPIOA, GPIO_PIN_1, GPIO_DIR_OUT);
}
void Systick_Delay_ms(uint32_t ms)
{
uint32_t i;
/* SYSTICK configuration */
SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK); // 即默认选择了外部参考时钟HSI(8MHz/8)
SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000); // (CK_SYS/8/1000) = 1ms
SYSTICK_IntConfig(DISABLE); // 不开启中断
/* 打开SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
for( i = 0;i < ms;i++ )
{
while( !( (SysTick->CTRL) & (1<<16) ) );
}
/* 关闭SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_DISABLE);
/* 复位SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
}
void Systick_Delay_us(uint32_t us)
{
uint32_t i;
/* SYSTICK configuration */
SYSTICK_ClockSourceConfig(SYSTICK_SRC_STCLK); // 即默认选择了外部参考时钟HSI(8MHz/8)
SYSTICK_SetReloadValue(SystemCoreClock / 8 / 1000000); // (CK_SYS/8/1000000) = 1us
SYSTICK_IntConfig(DISABLE); // 不开启中断
/* 打开SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
SYSTICK_CounterCmd(SYSTICK_COUNTER_ENABLE);
for( i = 0;i < us;i++ )
{
while( !( (SysTick->CTRL) & (1<<16) ) );
}
/* 关闭SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_DISABLE);
/* 复位SysTick计数器 */
SYSTICK_CounterCmd(SYSTICK_COUNTER_CLEAR);
}
/******************************************************************************
* Function Name --> IIC启动
* Description --> SCL高电平期间,SDA由高电平突变到低电平时启动总线
* SCL: __________
* \__________
* SDA: _____
* \_______________
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_Start(void)
{
IIC_RTC_SDA_OUT();
IIC_SDA_SET();
IIC_SCL_SET(); //在SCL高电平时,SDA为下降沿时候总线停止
Systick_Delay_us(2);
IIC_SDA_RESET();
Systick_Delay_us(2);
IIC_SCL_RESET();
}
/******************************************************************************
* Function Name --> IIC停止
* Description --> SCL高电平期间,SDA由低电平突变到高电平时停止总线
* SCL: --------
* __________
* SDA: _________/
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
void IIC_Stop(void)
{
IIC_RTC_SDA_OUT();
IIC_SDA_RESET();
IIC_SCL_SET();
Systick_Delay_us(2);
IIC_SDA_SET();
}
/******************************************************************************
* Function Name --> IIC应答
* Description -->
_ _
* SCL: _/ \_/ \_
* ___ _
* SDA: \_/
* Input --> none
* Output --> none
* Reaturn --> none
******************************************************************************/
uint8_t IN_SDA(void)
{
IIC_RTC_SDA_IN();
if(GPIO_ReadInBit(HT_GPIOA, GPIO_PIN_1))
{
// Usart_Sendbyte(HT_USART1,0x01);
return 1;
}
else
{
// Usart_Sendbyte(HT_USART1,0x00);
return 0;
}
}
void IIC_Ack(uint8_t a)
{
IIC_RTC_SDA_OUT();
if(a) IIC_SDA_SET();
else IIC_SDA_RESET();
IIC_SCL_SET();
Systick_Delay_us(2);
IIC_SCL_RESET();
}
/******************************************************************************
* Function Name --> 向IIC总线发送一个字节数据
* Description --> 向 BM8563 写一个字节的数据
* Input --> dat:要发送的数据
* Output --> none
* Reaturn --> ack:返回应答信号
******************************************************************************/
void IIC_Write_Byte(uint8_t data)
{
uint8_t i;
IIC_RTC_SDA_OUT();
IIC_SCL_RESET();
for(i=0;i<8;i++)
{
if((data<<i)&0x80)
{
IIC_SDA_SET();
}
else
{
IIC_SDA_RESET();
}
IIC_SCL_SET();
Systick_Delay_us(2);
IIC_SCL_RESET();
}
IIC_SDA_RESET(); //释放数据线
Systick_Delay_us(2);
if(IN_SDA())//读取应答信号
{
ack = 1;
}
else
{
ack = 0;
}
IIC_SCL_SET(); //为SCL下降做准备
Systick_Delay_us(2);
IIC_SCL_RESET();
}
/******************************************************************************
* Function Name --> 从IIC总线上读取一个字节数据
* Description --> none
* Input --> none
* Output --> none
* Reaturn --> x:读取到的数据
******************************************************************************/
uint8_t IIC_Read_Byte(void)
{
uint8_t i;
uint8_t data = 0;
IIC_RTC_SDA_IN();
for(i=0;i<8;i++)
{
data = data << 1;
if(IN_SDA())
{
data = data+1;
// Usart_Sendbyte(HT_USART1,data);
}
IIC_SCL_SET();
Systick_Delay_us(2);
IIC_SCL_RESET();
}
return data; //返回读取到的数据
}
uint8_t BM8563_Write(uint8_t sla,uint8_t suba,uint8_t data)
{
IIC_Start();
IIC_Write_Byte(sla);
if(ack==1) return 0;
IIC_Write_Byte(suba);
if(ack==1) return 0;
IIC_Write_Byte(data);
if(ack==1) return 0;
IIC_Stop();
return 1;
}
uint8_t BM8563_Read(uint8_t sla,uint8_t suba)
{
uint8_t data;
uint8_t i;
uint8_t trdata[7]={0};
IIC_Start();
IIC_Write_Byte(sla-1);
if(ack==1) return 0;
IIC_Write_Byte(suba);
if(ack==1) return 0;
IIC_Start();
IIC_Write_Byte(sla);
if(ack==1) return 0;
for(i=0; i<7; i++)
{
data = IIC_Read_Byte();
IIC_Ack(0);
if(i==0) trdata[i] = data&0x7F;//秒
if(i==1) trdata[i] = data&0x7F;//分
if(i==2) trdata[i] = data&0x3F;//时
if(i==3) trdata[i] = data&0x3F;//日
if(i==4) trdata[i] = data&0x07;//星期
if(i==5) trdata[i] = data&0x1F;//月
if(i==6) trdata[i] = data&0xFF;//年
Usart_Sendbyte(HT_USART1,trdata[i]);
}
IIC_Stop();
return 1;
}
uint8_t BM8563_Read_data(uint8_t sla,uint8_t suba,uint8_t *s, uint8_t length)
{
uint8_t data;
uint8_t i;
IIC_Start();
IIC_Write_Byte(sla-1);
if(ack==1) return 0;
IIC_Write_Byte(suba);
if(ack==1) return 0;
IIC_Start();
IIC_Write_Byte(sla);
if(ack==1) return 0;
for(i=0; i<length; i++)
{
data = IIC_Read_Byte();
IIC_Ack(0);
ReadData[i] = data;
}
IIC_Stop();
return 1;
}
void BM8563_Init(void)//时间初始化2022.8.15.星期一.16:31:50
{
BM8563_Write(0xA2,0x00,0x00);//控制状态寄存器0
BM8563_Write(0xA2,0x01,0x00);//控制状态寄存器1
BM8563_Write(0xA2,0x02,0x50);//秒
BM8563_Write(0xA2,0x03,0x31);//分
BM8563_Write(0xA2,0x04,0x16);//小时
BM8563_Write(0xA2,0x05,0x15);//日
BM8563_Write(0xA2,0x06,0x01);//星期
BM8563_Write(0xA2,0x07,0x08);//月
BM8563_Write(0xA2,0x08,0x22);//年
}
//-----------------------------------------------------------------------------
#include "ht32.h"
#include "ht32_board.h"
#include "led.h"
#include "key.h"
#include "time.h"
#include "pwm.h"
#include "usart.h"
#include "ht32f5xxxx_gpio.h"
#include "iic.h"
#include "stdio.h"
//-----------------------------------------------------------------------------
//static void delay(uint16_t data)
//{
// uint16_t i;
//
// while(data--)
// {
// for(i=0; i<1000; i++);
// }
//
//}
uint8_t i;
static void Init()
{
Key_Init();
Timer_Init();
Led_Init();
USART_Configuration();//串口初始化
IIC_Init();
// GPTM_PWM_init();
}
int main(void)
{
Init();
Systick_Delay_ms(20);
BM8563_Init();
Systick_Delay_ms(20);
while(1)
{
BM8563_Read(0xA3,0x02);
Systick_Delay_ms(1000);
}
}