#include "hal_pca8565.h" #include "hc32_ll_gpio.h" #include "FreeRTOS.h" #include "task.h" #define IIC_ERR 0 #define IIC_OK 1 #define READ_SDA2 GPIO_ReadInputPins(GPIO_PORT_B,GPIO_PIN_12) #define IIC_SDA2(n) (n?GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_12):GPIO_ResetPins(GPIO_PORT_B, GPIO_PIN_12)) #define IIC_SCL2(n) (n?GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_13):GPIO_ResetPins(GPIO_PORT_B, GPIO_PIN_13)) #define pca8565_speed 5 //需要示波器调1us的时间 static void delay_us(uint16_t time) { uint16_t i; for(i=time;i>0;i--) { __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); __nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop(); } } void iicx_init(void) { stc_gpio_init_t pstcGpioInit1; GPIO_StructInit(&pstcGpioInit1); pstcGpioInit1.u16PinDir = PIN_DIR_OUT; pstcGpioInit1.u16PinState = PIN_STAT_RST; GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit1); GPIO_Init(GPIO_PORT_B, GPIO_PIN_13,&pstcGpioInit1); GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_12); GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_13); } static void SDA_IN2(void) { stc_gpio_init_t pstcGpioInit3;//iic的引脚 pstcGpioInit3.u16PinDir = PIN_DIR_IN; GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit3); } static void SDA_OUT2(void) { stc_gpio_init_t pstcGpioInit3; pstcGpioInit3.u16PinDir = PIN_DIR_OUT; pstcGpioInit3.u16PinOutputType=PIN_OUT_TYPE_NMOS; GPIO_Init(GPIO_PORT_B, GPIO_PIN_12,&pstcGpioInit3); } static void iic_start(void) { SDA_OUT2(); IIC_SDA2(1); IIC_SCL2(1); delay_us(pca8565_speed); IIC_SDA2(0); delay_us(pca8565_speed); IIC_SCL2(0); } static void iic_stop(void) { SDA_OUT2(); IIC_SCL2(0); IIC_SDA2(0); delay_us(pca8565_speed); IIC_SCL2(1); IIC_SDA2(1); delay_us(pca8565_speed); } static void iic_ack(void) { SDA_OUT2(); IIC_SCL2(0); IIC_SDA2(0); delay_us(pca8565_speed); IIC_SCL2(1); delay_us(pca8565_speed); IIC_SCL2(0); } static void iic_nack(void) { SDA_OUT2(); IIC_SCL2(0); IIC_SDA2(1); delay_us(pca8565_speed); IIC_SCL2(1); delay_us(pca8565_speed); IIC_SCL2(0); } static uint8_t iic_wait_ack(void) { uint16_t t =200; SDA_OUT2(); IIC_SDA2(1);delay_us(1); IIC_SCL2(1);delay_us(1); SDA_IN2(); while(READ_SDA2) { t--; if(t==0) { iic_stop(); return 1; } delay_us(1); } IIC_SCL2(0); return 0; } static void iic_send_byte(uint8_t byte) { uint8_t bit_cnt; SDA_OUT2(); IIC_SCL2(0); for(bit_cnt=0;bit_cnt<8;bit_cnt++) { if(byte&0x80) IIC_SDA2(1); else IIC_SDA2(0); byte<<=1; delay_us(pca8565_speed); IIC_SCL2(1); delay_us(pca8565_speed); IIC_SCL2(0); } } static uint8_t iic_recive_byte(unsigned char ack) { uint8_t retc = 0; uint8_t bit_cnt; SDA_IN2(); for(bit_cnt=0;bit_cnt<8;bit_cnt++) { IIC_SCL2(0); delay_us(pca8565_speed); IIC_SCL2(1); retc=retc<<1; if(READ_SDA2) retc++; delay_us(pca8565_speed); } return(retc); } /* ************************************************************ * 函数名称: Pcf8563_IIC_WriteByte * * 函数功能: 软件IIC读取一个字节 * * 入口参数: slaveAddr:从机地址 * regAddr:寄存器地址 * val:需要读取的数据缓存 * * 返回参数: 1-成功 0-失败 * * 说明: ************************************************************ */ void Pcf8563_IIC_ReadByte ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Val ) { // //起始信号 // iic_start(); // //发送设备地址(写) // if(!iic_send_byte ( SlaveAddr )) //等待应答 // return IIC_ERR; // //发送寄存器地址 // if(!iic_send_byte ( RegAddr )) //等待应答 // return IIC_ERR; // iic_start(); //重启信号 // //发送设备地址(读) // if(!iic_send_byte ( SlaveAddr + 1 )) //等待应答 // return IIC_ERR; // *Val = iic_recive_byte (0); //产生一个非应答信号,代表读取接收 // iic_stop(); //停止信号 // return IIC_OK; iic_start(); iic_send_byte(SlaveAddr); iic_wait_ack(); iic_send_byte(RegAddr); iic_wait_ack(); iic_start(); iic_send_byte(SlaveAddr|0x01); iic_wait_ack(); *Val = iic_recive_byte(0); iic_stop(); } /* ************************************************************ * 函数名称: Pcf8563_IIC_WriteByte * * 函数功能: 软件IIC写一个字节 * * 入口参数: slaveAddr:从机地址 * regAddr:寄存器地址 * val:需要读取的数据缓存 * * 返回参数: 1-成功 0-失败 * * 说明: ************************************************************ */ void Pcf8563_IIC_WriteByte ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Val ) { // iic_start(); //起始信号 // //发送设备地址(写) // if (!iic_send_byte ( SlaveAddr )) //等待应答 // return IIC_ERR; // //发送寄存器地址 // if (!iic_send_byte ( RegAddr ) ) //等待应答 // return IIC_ERR; // if (!iic_send_byte ( *Val ) ) // return IIC_ERR; // // iic_stop(); //停止信号 // return IIC_OK; iic_start(); iic_send_byte(SlaveAddr); iic_wait_ack(); iic_send_byte(RegAddr); iic_wait_ack(); iic_send_byte(*Val); iic_wait_ack(); iic_stop(); } /* ************************************************************ * 函数名称: Pcf8563_IIC_WriteBytes * * 函数功能: 软件IIC写多个数据 * * 入口参数: slaveAddr:从机地址 * regAddr:寄存器地址 * buf:需要写入的数据缓存 * num:数据长度 * * 返回参数: 1-成功 0-失败 * * 说明: ************************************************************ */ _Bool Pcf8563_IIC_WriteBytes ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Buf, unsigned char Num ) { iic_start(); //起始信号 //发送设备地址(写) iic_send_byte ( SlaveAddr ); //等待应答 iic_wait_ack(); //发送寄存器地址 iic_send_byte ( RegAddr ) ; //等待应答 iic_wait_ack(); while ( Num-- ) //循环写入数据 { //发送数据 iic_send_byte ( *Buf ); //等待应答 iic_wait_ack(); Buf++; //数据指针偏移到下一个 delay_us(10); } iic_stop(); //停止信号 return IIC_OK; } /* ************************************************************ * 函数名称: Pcf8563_IIC_ReadBytes * * 函数功能: 软件IIC读多个数据 * * 入口参数: slaveAddr:从机地址 * regAddr:寄存器地址 * buf:需要写入的数据缓存 * num:数据长度 * * 返回参数: 1-成功 0-失败 * * 说明: ************************************************************ */ _Bool Pcf8563_IIC_ReadBytes ( unsigned char SlaveAddr, unsigned char RegAddr, unsigned char *Buf, unsigned char Num ) { iic_start(); //起始信号 //发送设备地址(写) iic_send_byte ( SlaveAddr ); //等待应答 iic_wait_ack(); //发送寄存器地址 iic_send_byte ( RegAddr ); //等待应答 iic_wait_ack(); iic_start(); //重启信号 //发送设备地址(读) iic_send_byte ( SlaveAddr + 1 ); //等待应答 iic_wait_ack(); while ( Num-- ) { //偏移到下一个数据存储地址 if ( Num == 0 ) { *Buf = iic_recive_byte ( 0 ); //最后一个数据需要回NOACK } else { *Buf = iic_recive_byte ( 1 ); //回应ACK } Buf++; } iic_stop(); return IIC_OK; } //常量定义 const char week_day[7][10]={"SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"}; const int8_t months[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; //变量定义 rtc_time_st rtc_time; /* ************************************************************ * 函数名称: Pcf8563_Rtc_Init * * 函数功能: 外置RTC初始化 * * 入口参数: 无 * * 返回参数: 无 * * 说明: STATUS1:正常模式、POR disabled * STATUS2:INT is active when TF is active * read: alarm flag inactive * write: alarm flag is cleared * read: timer flag inactive * write: timer flag is cleared * alarm interrupt disabled * timer interrupt disabled * CLKOUT:CLKOUT output is activated * frequency output at pin CLKOUT is 1.024 kHz(为何设置为该值) ************************************************************ */ void rtc_init(void) { iicx_init(); } void Pcf8563_Rtc_Init(void) { DDL_DelayMS(20); Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CONTROL_STATUS1,0x00); //默认 Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CONTROL_STATUS2,0x00); //默认 Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_CLKOUT,0x80); //使能CLK输出,1024Hz } /* ************************************************************ * 函数名称: Get_Pcf8563_Rtc_Time * * 函数功能: 获取外置RTC时间 * * 入口参数: rtc_time * * 返回参数: 无 * * 说明: 读时间 年、月、日、时、分、日期 week为指针指向week_day数组 ************************************************************ */ void Get_Pcf8563_Rtc_Time(rtc_time_st *rtc_time) { uint8_t time_buf[7]={0}; Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x02,&time_buf[0]);//秒 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x03,&time_buf[1]);//分 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x04,&time_buf[2]);//时 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x05,&time_buf[3]);//日 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x06,&time_buf[4]);//星期 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x07,&time_buf[5]);//月 Pcf8563_IIC_ReadByte(PCF8563_SLAVE_ADDRESS,0x08,&time_buf[6]);//年 //将时间从BCD编码变成十进制 rtc_time->sec=BCDToDec(time_buf[0] & 0X7F); //秒 rtc_time->min=BCDToDec(time_buf[1] & 0X7F); //分 rtc_time->hour=BCDToDec(time_buf[2] & 0X3F); //时 rtc_time->date=BCDToDec(time_buf[3] & 0X3F); //日 // rtc_time->week=(time_buf[4] & 0X07); //星期(值0为星期7 1为星期1) rtc_time->week=week_day[(time_buf[4] & 0X07)]; //星期(字符串指针) rtc_time->mon=BCDToDec(time_buf[5] & 0X1F); //月 rtc_time->year=2000 + (uint16_t)BCDToDec(time_buf[6]); //年 // for(int i = 0;i < 7; i++) // printf("%x ",time_buf[i]); } /* ************************************************************ * 函数名称: LogRtcTime * * 函数功能: LogRtcTime * * 入口参数: rtc_time * * 返回参数: 无 * * 说明: 读时间 年、月、日、时、分、日期 week为指针指向week_day数组 ************************************************************ */ void LogRtcTime(rtc_time_st *rtc_time) { printf("data:%4d-%02d-%02d %02d:%02d:%02d week:%s\r\n",rtc_time->year,rtc_time->mon,rtc_time->date,rtc_time->hour,rtc_time->min,rtc_time->sec,rtc_time->week); } /* ************************************************************ * 函数名称: Set_Pcf8563_Rtc_Time * * 函数功能: 获取外置RTC时间 * * 入口参数: year mon date hour min sec * * 返回参数: 无 * * 说明: 设置RTC时间 week为0-7 0为星期7 1为星期1 ************************************************************ */ void Set_Pcf8563_Rtc_Time(uint16_t year,uint8_t mon,uint8_t date,uint8_t hour,uint8_t min,uint8_t sec,uint8_t week) { //将时间从十进制变成BCD编码 uint8_t time_buf[7]={0}; time_buf[6] = DecToBCD((uint8_t)(year-2000)); time_buf[5] = DecToBCD(mon); time_buf[4] = week; time_buf[3] = DecToBCD(date); time_buf[2] = DecToBCD(hour); time_buf[1] = DecToBCD(min); time_buf[0] = DecToBCD(sec); // for(int i = 0;i < 7; i++) // printf("%x ",time_buf[i]); // printf("\n"); Pcf8563_IIC_WriteBytes(PCF8563_SLAVE_ADDRESS,PCF8563_ADDR_SEC,time_buf,7); } /* ************************************************************ * 函数名称: DecToBCD * * 函数功能: DecToBCD * * 入口参数: unsigned char * * 返回参数: unsigned char * * 说明: 十进制转BCD编码 ************************************************************ */ unsigned char DecToBCD(unsigned char _dec) { unsigned char temp = 0; while (_dec >= 10) { temp++; _dec -= 10; } return ((unsigned char)(temp << 4) | _dec); } /* ************************************************************ * 函数名称: BCDToDec * * 函数功能: BCDToDec * * 入口参数: unsigned char * * 返回参数: unsigned char * * 说明: BCD编码转十进制 ************************************************************ */ unsigned char BCDToDec(unsigned char _BCD) { unsigned char temp = 0; temp = ((unsigned char)(_BCD & (unsigned char)0xF0) >> (unsigned char)0x04) * 10; return (temp + (_BCD & (unsigned char)0x0F)); } /* ************************************************************ * 函数名称: Days_Count * * 函数功能: 计算日期之间的天数 * * 入口参数: rtc_time_st 起始和结束日期 * * 返回参数: 天数 * * 说明: ************************************************************ */ int Days_Count(rtc_time_st *start,rtc_time_st *stop) { int day_start=0; int day_stop=0; uint8_t i=0; if(start->year==stop->year) //同一年 { if(ISLOOP(start->year)) //闰年 { if(start->mon<=2) //计算开始的天数 { if(start->mon==1) day_start=0; else { day_start=day_start+months[0]; } } else { for(i=1;imon;i++) day_start=day_start+months[i-1]+1; } if(stop->mon<=2) //计算结束的的天数 { if(stop->mon==1) day_stop=0; else { day_stop=day_stop+months[0]; } } else { for(i=1;imon;i++) day_stop=day_stop+months[i-1]+1; } } else //平年 { if(start->mon==1) //计算开始的天数 day_start=0; else { for(i=1;imon;i++) day_start=day_start+months[i-1]; } if(stop->mon==1) //计算结束的的天数 day_stop=0; else { for(i=1;imon;i++) day_stop=day_stop+months[i-1]; } } return day_stop-day_start; } else //不同年(此时一定12月和1月) { return 31-start->date+stop->date; } } /*************************************RTC定时唤醒**********************************************/ void P8563_alarm(unsigned char min) { min = DecToBCD(min); Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x9,min); /*分钟报警*/ Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x12); /*报警有效*/ //使能报警器和定时器发出中断请求 } void clear_alarm(void) { Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x02);//清中断标志 } /******************关闭闹钟中断***************************/ void close_alarm(void) { Pcf8563_IIC_WriteByte(PCF8563_SLAVE_ADDRESS,0x01,0x00);//禁止中断 } #include "string.h" #include "FreeRTOS.h" #include "FreeRTOSConfig.h" #include "task.h" void pca8565_task(void *argv) { Pcf8563_Rtc_Init(); Set_Pcf8563_Rtc_Time(2023,5,19,15,11,33,5);//33 22 16 17 3 5 23 while(1) { Get_Pcf8563_Rtc_Time(&rtc_time); LogRtcTime(&rtc_time); vTaskDelay(1000); } }