STM32-HAL库(下2)

STM32-HAL库(下2)

208-209 实时时钟项目完结

(1)参考"56. 实时时钟项目",主函数中编写实时闹钟流程图业务逻辑代码;-(56. 实时时钟项目-main.c,rtc.c,beep.c,key.c,oled.c,rtc.h,beep.h,key.h,oled.h,font.h)-待测试

/*
-------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"
#include "beep.h"
#include "key.h"
#include "oled.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    rtc_init();
    beep_init();
    key_init();
    oled_init();
    printf("hello world!\r\n");
    rtc_write_bkp(1,0xAAAA);//1为寄存器号,BKP备份寄存器有42个寄存器
    printf("读出值为:%X\r\n",rtc_read_bkp(1));
    uint8_t time_data[6] = {24,1,1,10,30,30};
    uint8_t alarm_data[3] = {10,10,10};
    uint8_t set_time_shift = TIME_SECOND;
    uint8_t set_alarm_shift = ALARM_SECOND;
    uint8_t set_time_flag = 0,set_alarm_flag = 0;
    if(rtc_read_bkp(1) != 0xAAAA)
    {
        rtc_write_bkp(1,0xAAAA);
        rtc_set_time(time_data);
        rtc_set_alarm(alarm_data);
    }
    while(1)
    { 
        rtc_get_time(time_data);
        rtc_get_alarm(alarm_data);
        oled_show_time_alarm(time_data,alarm_data);
        switch(key_scan())
        {
            case KEY_SET:
                //进入时间设置模式
                set_time_flag = 1;
                while(set_time_flag)
                {
                    //闪动要修改的坑位
                    oled_show_element(time_data[set_time_shift],OFF,set_time_shift);
                    delay_ms(100);
                    oled_show_element(time_data[set_time_shift],ON,set_time_shift);
                    delay_ms(100);
                    switch(key_scan())
                    {
                        case KEY_SET:
                            set_time_flag = 0;
                            set_time_shift = TIME_SECOND;
                            rtc_set_time(time_data);
                            break;
                        case KEY_SHIFT:
                            if(set_time_shift -- <= TIME_YEAR)
                                set_time_shift = TIME_SECOND;
                            break;
                        case KEY_UP:
                            if(set_time_shift == TIME_SECOND || set_time_shift == TIME_MINUTE) //分、秒
                                if(time_data[set_time_shift] < 59)
                                    time_data[set_time_shift]++;
                           if(set_time_shift == TIME_HOUR)                             //时
                                if(time_data[set_time_shift] < 23)
                                    time_data[set_time_shift]++;
                                
                            if(set_time_shift == TIME_DAY)                             //日
                                if(time_data[set_time_shift] < 31)
                                    time_data[set_time_shift]++;
                                
                            if(set_time_shift == TIME_MONTH)                             //月
                                if(time_data[set_time_shift] < 12)
                                    time_data[set_time_shift]++;
                                
                            if(set_time_shift == TIME_MONTH)                             //年
                                if(time_data[set_time_shift] < 99)
                                    time_data[set_time_shift]++;
                            break;
                         case KEY_DOWN:
                                if(time_data[set_time_shift] > 0)
                                        time_data[set_time_shift]--;
                            break;
                    
                    }
                }
                break;
            case KEY_SHIFT:
                //进入闹钟设置模式
                set_alarm_flag = 1;
                while(set_alarm_flag)
                {
                    //闪动要修改的坑位
                    oled_show_element(alarm_data[set_alarm_shift - ALARM_HOUR],OFF,set_alarm_shift);
                    delay_ms(100);
                    oled_show_element(alarm_data[set_alarm_shift - ALARM_HOUR],ON,set_alarm_shift);
                    delay_ms(100);
                    switch(key_scan())
                    {
                        case KEY_SET:
                            set_alarm_flag = 0;
                            set_alarm_shift = ALARM_SECOND;
                            rtc_set_alarm(alarm_data);
                            break;
                        case KEY_SHIFT:
                            if(set_alarm_shift -- <= ALARM_HOUR)
                                set_alarm_shift = ALARM_SECOND;
                            break;
                        case KEY_UP:
                            if(alarm_data[set_alarm_shift - ALARM_HOUR] < 59)
                                alarm_data[set_alarm_shift - ALARM_HOUR]++;                                
                            break;
                        case KEY_DOWN:
                            if(alarm_data[set_alarm_shift - ALARM_HOUR] > 0)
                                alarm_data[set_alarm_shift - ALARM_HOUR]--;                             
                            break;
                        default:
                            break;
                    }
                }
                break;
            case KEY_UP:
            case KEY_DOWN:
                beep_off();
                break;
            default:
                break;
        
        }
    }
}

/*
-------------------------------------------------------------------------
rtc.c:
-------------------------------------------------------------------------
*/
#include "rtc.h"
#include "stdio.h"

RTC_HandleTypeDef rtc_handle = {0};
//rtc初始化函数rtc_init()
void rtc_init(void)
{
    __HAL_RCC_BKP_CLK_ENABLE();
    __HAL_RCC_PWR_CLK_ENABLE();
//HAL_StatusTypeDef HAL_RTC_Init(RTC_HandleTypeDef *hrtc)
    HAL_PWR_EnableBkUpAccess();
    rtc_handle.Instance = RTC;
    rtc_handle.Init.AsynchPrediv = 32767;//分频系数,此处选低速外部时钟LSE 32.768kHz,分频系数填32767,实际上会加1为37768
    rtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;//不适用侵入检测
    HAL_RTC_Init(&rtc_handle);
}    
//msp函数HAL_RTC_MspInit()

void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{
    __HAL_RCC_RTC_ENABLE();
    RCC_OscInitTypeDef osc_instruct = {0};
    RCC_PeriphCLKInitTypeDef periphclk_initstruct = {0};
    osc_instruct.OscillatorType =RCC_OSCILLATORTYPE_LSE;//振荡器类型为低速外部时钟
    osc_instruct.LSEState =RCC_LSE_ON;//低速外部时钟状态,开启
    osc_instruct.PLL.PLLState =RCC_PLL_NONE;//锁相环状态,没用到锁相环
    HAL_RCC_OscConfig(&osc_instruct);
    periphclk_initstruct.PeriphClockSelection =RCC_PERIPHCLK_RTC;//外设时钟选择,RTC
    periphclk_initstruct.RTCClockSelection =RCC_RTCCLKSOURCE_LSE;//RTC时钟选择,低速外部时钟
    HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);
    HAL_NVIC_SetPriority(RTC_Alarm_IRQn,2,2); 
    HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); //闹钟中断开启
}    

//闹钟中断处理函数RTC_Alarm_IRQHandler()
void RTC_Alarm_IRQHandler(void)
{
    HAL_RTC_AlarmIRQHandler(&rtc_handle);
}    

//闹钟回调函数HAL_RTC_AlarmAEventCallback()
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    printf("ring ring ring ...\r\n");

}    
//rtc读bkp函数rtc_read_bkp()
uint16_t rtc_read_bkp(uint8_t bkrx) //bkrx为寄存器号,BKP备份寄存器有42个寄存器
{
    uint8_t data = 0;
    data  = HAL_RTCEx_BKUPRead(&rtc_handle,bkrx);
    return (uint16_t)data;
}

//rtc写入bkp函数rtc_write_bkp
void rtc_write_bkp(uint8_t bkrx,uint16_t data)
{
    HAL_RTCEx_BKUPWrite(&rtc_handle,bkrx,data);          
}    
//时间获取函数rtc_get_time()
void rtc_get_time(uint8_t *time_data)
{
    RTC_TimeTypeDef rtc_time ={0};
    RTC_DateTypeDef rtc_date ={0};
    //HAL_StatusTypeDef HAL_RTC_GetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
    //HAL_StatusTypeDef HAL_RTC_GetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
    HAL_RTC_GetTime(&rtc_handle,&rtc_time,RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&rtc_handle,&rtc_date,RTC_FORMAT_BIN);
    time_data[0] = rtc_date.Year;
    time_data[1] = rtc_date.Month;
    time_data[2] =rtc_date.Date;
    time_data[3] =rtc_time.Hours;
    time_data[4] =rtc_time.Minutes;
    time_data[5] =rtc_time.Seconds;  
    //printf("rtc time:%d-%02d-%02d :%02d:%02d:%02d",rtc_date.Year + 2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes,rtc_time.Seconds);  
}    


//时间设置函数rtc_set_time()
void rtc_set_time(uint8_t *time_date)
{
    RTC_DateTypeDef rtc_date = {0};
    RTC_TimeTypeDef rtc_time = {0};
    //HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format)
    //HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format)
    rtc_date.Year = time_date[0];
    rtc_date.Month = time_date[1];
    rtc_date.Date = time_date[2];
    HAL_RTC_SetDate(&rtc_handle,&rtc_date,RTC_FORMAT_BIN);
    rtc_time.Hours = time_date[3];
    rtc_time.Minutes = time_date[4];
    rtc_time.Seconds = time_date[5];
    HAL_RTC_SetTime(&rtc_handle,&rtc_time,RTC_FORMAT_BIN);
    while(!__HAL_RTC_ALARM_GET_FLAG(&rtc_handle,RTC_FLAG_RTOFF));//RTOFF标志位为0一直等待,由于对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行
}    

//设置闹钟函数rtc_set_alarm();   
void rtc_set_alarm(uint8_t *alarm_date)
{
    RTC_AlarmTypeDef alarm ={0};
    alarm.Alarm = RTC_ALARM_A;
    alarm.AlarmTime.Hours = alarm_date[0];
    alarm.AlarmTime.Minutes = alarm_date[1];
    alarm.AlarmTime.Seconds = alarm_date[2];
    //HAL_StatusTypeDef HAL_RTC_SetAlarm_IT(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Format)   
    HAL_RTC_SetAlarm_IT(&rtc_handle,&alarm,RTC_FORMAT_BIN);
}  

//闹钟获取函数rtc_get_alarm()
void rtc_get_alarm(uint8_t *alarm_date)
{
    RTC_AlarmTypeDef alarm = {0};
    alarm_date[0] = alarm.AlarmTime.Hours;
    alarm_date[1] = alarm.AlarmTime.Minutes;
    alarm_date[2] = alarm.AlarmTime.Seconds;
    //HAL_StatusTypeDef HAL_RTC_GetAlarm(RTC_HandleTypeDef *hrtc, RTC_AlarmTypeDef *sAlarm, uint32_t Alarm, uint32_t Format)
    HAL_RTC_GetAlarm(&rtc_handle,&alarm,RTC_ALARM_A,RTC_FORMAT_BIN);
}    


/*
-------------------------------------------------------------------------
beep.c:
-------------------------------------------------------------------------
*/
#include "beep.h"
#include "sys.h"
//初始化GPIO函数
void beep_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    //调用GPIO初始化函数
//    HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)

    gpio_initstruct.Pin = GPIO_PIN_5; // BEEP及LED2对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽输出
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOB,&gpio_initstruct);
    //关闭LED
    beep_off();
}
//点亮BEEP函数
void beep_on(void)
{
    //void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); // 拉低BEEP引脚,点亮BEEP
}
//熄灭BEEP函数
void beep_off(void)
{
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET); // 拉高BEEP引脚,熄灭BEEP
}

//翻转BEEP状态函数
void beep_toggle(void)
{
    //void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_5);
}



/*
-------------------------------------------------------------------------
key.c:
-------------------------------------------------------------------------
*/
#include "key.h"
#include "sys.h"
#include "delay.h"

//初始化GPIO
void key_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    //调用GPIO初始化函数
    // HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
    gpio_initstruct.Pin = GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; // 输入
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}

//按键扫描函数
uint8_t key_scan(void){
    //GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET);
            //返回按键值
            return KEY_SET;
        }       
    }
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_SET);
            //返回按键值
            return KEY_SHIFT;
        }     
    }
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_3) == GPIO_PIN_SET);
            //返回按键值
            return KEY_UP;
        }     
    }
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_SET);
            //返回按键值
            return KEY_DOWN;
        }     
    }    
    //返回默认值
    return 0;
}




/*
-------------------------------------------------------------------------
oled.c:
-------------------------------------------------------------------------
*/
#include "oled.h"
#include "delay.h"
#include "font.h"
void oled_gpio_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    OLED_I2C_SCL_CLK();
    OLED_I2C_SDA_CLK();
    gpio_initstruct.Pin = OLED_I2C_SCL_PIN;
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_initstruct.Pull = GPIO_PULLUP;
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(OLED_I2C_SCL_PORT,&gpio_initstruct);
    gpio_initstruct.Pin = OLED_I2C_SDA_PIN;
    HAL_GPIO_Init(OLED_I2C_SDA_PORT,&gpio_initstruct);    
}   

void oled_i2c_start(void)
{
    OLED_SCL_SET();
    OLED_SDA_SET();
    OLED_SDA_RESET();
    OLED_SCL_RESET();
    
}

void oled_i2c_stop(void)
{
    OLED_SCL_SET();
    OLED_SDA_RESET();
    OLED_SDA_SET();
}    

void oled_i2c_ack(void)
{
    OLED_SCL_SET();
    OLED_SCL_RESET();
} 

void oled_i2c_write_byte(uint8_t data)
{
    uint8_t i,tmp;
    tmp = data;
    for(i=0;i<8;i++)
    {
        if((tmp & 0x80) == 0x80)
            OLED_SDA_SET();
        else
            OLED_SDA_RESET();
        tmp = tmp <<1;
        OLED_SCL_SET();
        OLED_SCL_RESET();
    }
}

void oled_write_cmd(uint8_t cmd)
{
    oled_i2c_start();
    oled_i2c_write_byte(0x78);
    oled_i2c_ack();
    oled_i2c_write_byte(0x00);
    oled_i2c_ack();
    oled_i2c_write_byte(cmd);
    oled_i2c_ack();
    oled_i2c_stop();
}

void oled_write_data(uint8_t data)
{
    oled_i2c_start();
    oled_i2c_write_byte(0x78);
    oled_i2c_ack();
    oled_i2c_write_byte(0x40);
    oled_i2c_ack();
    oled_i2c_write_byte(data);
    oled_i2c_ack();
    oled_i2c_stop();
}    

void oled_init(void)
{
    oled_gpio_init();
    delay_ms(100);
    
    oled_write_cmd(0xAE);    //设置显示开启/关闭,0xAE关闭,0xAF开启

    oled_write_cmd(0xD5);    //设置显示时钟分频比/振荡器频率
    oled_write_cmd(0x80);    //0x00~0xFF

    oled_write_cmd(0xA8);    //设置多路复用率
    oled_write_cmd(0x3F);    //0x0E~0x3F

    oled_write_cmd(0xD3);    //设置显示偏移
    oled_write_cmd(0x00);    //0x00~0x7F

    oled_write_cmd(0x40);    //设置显示开始行,0x40~0x7F

    oled_write_cmd(0xA1);    //设置左右方向,0xA1正常,0xA0左右反置

    oled_write_cmd(0xC8);    //设置上下方向,0xC8正常,0xC0上下反置

    oled_write_cmd(0xDA);    //设置COM引脚硬件配置
    oled_write_cmd(0x12);

    oled_write_cmd(0x81);    //设置对比度
    oled_write_cmd(0xCF);    //0x00~0xFF

    oled_write_cmd(0xD9);    //设置预充电周期
    oled_write_cmd(0xF1);

    oled_write_cmd(0xDB);    //设置VCOMH取消选择级别
    oled_write_cmd(0x30);

    oled_write_cmd(0xA4);    //设置整个显示打开/关闭

    oled_write_cmd(0xA6);    //设置正常/反色显示,0xA6正常,0xA7反色

    oled_write_cmd(0x8D);    //设置充电泵
    oled_write_cmd(0x14);

    oled_write_cmd(0xAF);    //开启显示    
}    

void oled_set_cursor(uint8_t x,uint8_t y)//x代表列,y代表行
{
    oled_write_cmd(0xB0 + y);
    oled_write_cmd((x&0x0F) | 0x00);
    oled_write_cmd(((x&0xF0)>>4) | 0x10);
}    

void oled_fill(uint8_t data)
{
    uint8_t i,j;
    for(i=0;i<8;i++)
    {
        for(j=0;j<128;j++)
        {
            oled_set_cursor(j,i);
            oled_write_data(data);
        }      
    }
}    

void oled_show_char(uint8_t x,uint8_t y,uint8_t num,uint8_t size)
{
    uint8_t i,j,page;
    num = num -'.';
    page = size / 8;
    if(size % 8)
        page ++;
    for(j = 0;j < page;j++)
    {
        oled_set_cursor(x,y + j);
        for(i=size / 2 * j;i < size /2*(j+1); i++ )
        {
            if(size == 12)
                oled_write_data(ascii_6X12[num][i]);
            else if(size == 16)
                oled_write_data(ascii_8X16[num][i]);
            else if(size == 24)
                oled_write_data(ascii_12X24[num][i]);        
        }
    }
}    

void oled_show_string(uint8_t x,uint8_t y,char *p,uint8_t size)
{
    while(*p !='\0')
    {
        oled_show_char(x,y,*p,size);
        x = x+size/2;
        p++;
    }
}    

//void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N, uint8_t size)
//{
//    uint16_t i, j;
//    for(j = 0; j < size/8; j++)
//    {
//        oled_set_cursor(x, y + j);
//        for(i = size *j; i < size * (j + 1); i++)
//        {
//            if(size == 16)
//                oled_write_data(chinese_16x16[N][i]);
//            else if(size == 24)
//                oled_write_data(chinese_24x24[N][i]);
//        }
//    }
//}

//oled_show_chinese()改写
void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N)
{
    uint8_t i,j;
    for(j = 0;j < 2; j++)
    {
        oled_set_cursor(x,y + j);
        for(i =16 * j; i <16 *(j + 1); i++)
            oled_write_data(chinese_time[N][i]);
    }
}    
//新增oled_show_init()显示初始化闹钟信息

void oled_show_init(void)
{
    oled_fill(0x00);
    oled_show_string(8, 0 ,"2000",16);              //2000
    oled_show_chinese(40, 0, 0);                    //年
    oled_show_string(56,0,"00",16);                 //00
    oled_show_chinese(72,0,1);                       //月
    oled_show_string(88, 0, "00", 16);              //00
    oled_show_chinese(104, 0, 2);                   //日
    
    oled_show_string(26, 2, "00", 16);              //00
    oled_show_char(45, 2, ':', 16);                 //:
    oled_show_string(56, 2, "00", 16);              //00
    oled_show_char(75, 2, ':', 16);                 //:
    oled_show_string(86, 2, "00", 16);              //00
    
    oled_show_chinese(10, 4, 3);                    //闹
    oled_show_chinese(26, 4, 4);                    //钟
    oled_show_char(42, 4, ':', 16);                 //:
    
    oled_show_string(26, 6, "00", 16);              //00
    oled_show_char(45, 6, ':', 16);                 //:
    oled_show_string(56, 6, "00", 16);              //00
    oled_show_char(75, 6, ':', 16);                 //:
    oled_show_string(86, 6, "00", 16);              //00       
}    

//oled_clear_2char()清空2个字节信息
void oled_clear_2char(uint8_t x,uint8_t y)
{
    uint8_t i =0;
    oled_set_cursor(x, y);
    for(i = 0;i < 16; i++)
    oled_write_data(0x00);
        oled_set_cursor(x, y);
    for(i = 0;i < 16; i++)
        oled_write_data(0x00);
}    

void oled_show_image(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t *bmp)
{
    uint8_t i, j;
    for(j = 0; j < height; j++)
    {
        oled_set_cursor(x, y + j);
        for(i = 0; i < width; i++)
            oled_write_data(bmp[width * j + i]);
    }
}


//显示年函数oled_show_year_()
void oled_show_year(uint8_t num,uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(24, 0,num/10 + '0', 16);
        oled_show_char(32, 0,num%10+ '0', 16);
    }
    else
        oled_clear_2char(24,0);
    
}    
//显示月函数oled_show_month()
void oled_show_month(uint8_t num,uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(56, 0, num/10 + '0', 16);
        oled_show_char(64, 0, num%10 + '0', 16);
    }
    else
        oled_clear_2char(56, 0);  
}    
//显示日函数oled_show_day()
void oled_show_day(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(88, 0, num/10 + '0', 16);
        oled_show_char(96, 0, num%10 + '0', 16);
    }
    else
        oled_clear_2char(88, 0);
}
//显示时函数oled_show_hour()
void oled_show_hour(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(26, 2, num/10 + '0', 16);
        oled_show_char(34, 2, num%10 + '0', 16);
    }
    else
        oled_clear_2char(26, 2);
}
//显示分函数oled_show_minute()
void oled_show_minute(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(56, 2, num/10 + '0', 16);
        oled_show_char(64, 2, num%10 + '0', 16);
    }
    else
        oled_clear_2char(56, 2);
}
//显示秒函数oled_show_second()
void oled_show_second(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(86, 2, num/10 + '0', 16);
        oled_show_char(94, 2, num%10 + '0', 16);
    }
    else
        oled_clear_2char(86, 2);
}
//显示闹钟时函数oled_show_alarm_hour()
void oled_show_alarm_hour(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(26, 6, num/10 + '0', 16);
        oled_show_char(34, 6, num%10 + '0', 16);
    }
    else
        oled_clear_2char(26, 6);
}
//显示闹钟分函数oled_show_alarm_minute()
void oled_show_alarm_minute(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(56, 6, num/10 + '0', 16);
        oled_show_char(64, 6, num%10 + '0', 16);
    }
    else
        oled_clear_2char(56, 6);
}
//显示闹钟秒函数oled_show_alarm_second()
void oled_show_alarm_second(uint8_t num, uint8_t display_flag)
{
    if(display_flag)
    {
        oled_show_char(86, 6, num/10 + '0', 16);
        oled_show_char(94, 6, num%10 + '0', 16);
    }
    else
        oled_clear_2char(86, 6);
}
//oled显示那个元素函数oled_show_element()
void oled_show_element(uint8_t num,uint8_t display_flag,uint8_t elements)
{
    switch(elements)
    {
        case TIME_YEAR:oled_show_year(num,display_flag);break;
        case TIME_MONTH:oled_show_year(num,display_flag);break;
        case TIME_DAY:oled_show_year(num,display_flag);break;
        case TIME_HOUR:oled_show_year(num,display_flag);break;
        case TIME_MINUTE:oled_show_year(num,display_flag);break;
        case TIME_SECOND:oled_show_year(num,display_flag);break;
        case ALARM_HOUR:oled_show_year(num,display_flag);break;
        case ALARM_MINUTE:oled_show_year(num,display_flag);break;
        case ALARM_SECOND:oled_show_year(num,display_flag);break;
        default:break;
        
    }
}    
//oled显示闹钟函数oled_show_time_alarm()
void oled_show_time_alarm(uint8_t *time,uint8_t *alarm)
{
    oled_show_year(time[0],1);
    oled_show_month(time[1],1);
    oled_show_day(time[2],1);
    oled_show_hour(time[3],1);
    oled_show_minute(time[4],1);
    oled_show_second(time[4],1);
    oled_show_alarm_hour(alarm[0],1);
    oled_show_alarm_minute(alarm[1],1);
    oled_show_alarm_second(alarm[2],1);
}


/*
-------------------------------------------------------------------------
rtc.h:
-------------------------------------------------------------------------
*/
#ifndef __RTC_H__
#define __RTC_H__
#include "sys.h"
#include "time.h"
void rtc_init(void);
uint16_t rtc_read_bkp(uint8_t bkrx);
void rtc_write_bkp(uint8_t bkrx,uint16_t data);
void rtc_get_time(uint8_t *time_data);
void rtc_set_time(uint8_t *time_date);
void rtc_set_alarm(uint8_t *alarm_date);
void rtc_get_alarm(uint8_t *alarm_date);
#endif

/*
-------------------------------------------------------------------------
beep.h:
-------------------------------------------------------------------------
*/
#ifndef __BEEP_H__
#define __BEEP_H__
void beep_init(void);
void beep_on(void);
void beep_off(void);
void beep_toggle(void);
#endif

/*
-------------------------------------------------------------------------
key.h:
-------------------------------------------------------------------------
*/
#ifndef __KEY_H__
#define __KEY_H__
#include "sys.h"
enum key_num
{
    KEY_SET = 1,
    KEY_SHIFT,
    KEY_UP,
    KEY_DOWN    
};
void key_init(void);
uint8_t key_scan(void);
#endif

/*
-------------------------------------------------------------------------
oled.h:
-------------------------------------------------------------------------
*/
#ifndef __OLED_H__
#define __OLED_H__
#include "sys.h"
#define OLED_I2C_SCL_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SCL_PORT   GPIOB
#define OLED_I2C_SCL_PIN    GPIO_PIN_8

#define OLED_I2C_SDA_CLK() __HAL_RCC_GPIOB_CLK_ENABLE()
#define OLED_I2C_SDA_PORT   GPIOB
#define OLED_I2C_SDA_PIN    GPIO_PIN_9

//void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
#define OLED_SCL_RESET()    HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_RESET)
#define OLED_SCL_SET()  HAL_GPIO_WritePin(OLED_I2C_SCL_PORT,OLED_I2C_SCL_PIN,GPIO_PIN_SET)

#define OLED_SDA_RESET()    HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_RESET)
#define OLED_SDA_SET()  HAL_GPIO_WritePin(OLED_I2C_SDA_PORT,OLED_I2C_SDA_PIN,GPIO_PIN_SET)


#define ON      1
#define OFF     0

enum elements
{
    TIME_YEAR = 0,
    TIME_MONTH,
    TIME_DAY,
    TIME_HOUR,
    TIME_MINUTE,
    TIME_SECOND,
    ALARM_HOUR,
    ALARM_MINUTE,
    ALARM_SECOND  
};

void oled_init(void);
void oled_write_cmd(uint8_t cmd);
void oled_write_data(uint8_t data);
void oled_set_cursor(uint8_t x,uint8_t y);
void oled_fill(uint8_t data);
void oled_show_char(uint8_t x,uint8_t y,uint8_t num,uint8_t size);
void oled_show_string(uint8_t x,uint8_t y,char *p,uint8_t size);
void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N);
void oled_show_init(void);
void oled_clear_2char(uint8_t x,uint8_t y);
void oled_show_image(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t *bmp);
void oled_show_element(uint8_t num,uint8_t display_flag,uint8_t elements);
void oled_show_time_alarm(uint8_t *time,uint8_t *alarm);
#endif

/*
-------------------------------------------------------------------------
font.h:
-------------------------------------------------------------------------
*/
#ifndef __FONT_H__
#define __FONT_H__


//16号汉字:实时时钟项目
const unsigned char chinese_time[][32] =
{
    0x00,0x20,0x18,0xC7,0x44,0x44,0x44,0x44,0xFC,0x44,0x44,0x44,0x44,0x04,0x00,0x00,
    0x04,0x04,0x04,0x07,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x04,0x04,0x00,/*"年",0*/
    0x00,0x00,0x00,0xFE,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0xFE,0x00,0x00,0x00,
    0x80,0x40,0x30,0x0F,0x02,0x02,0x02,0x02,0x02,0x02,0x42,0x82,0x7F,0x00,0x00,0x00,/*"月",1*/
    0x00,0x00,0x00,0xFE,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xFE,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0x00,0x00,0x00,0x00,/*"日",2*/
    0x00,0xF8,0x01,0x22,0x20,0x22,0x2A,0xF2,0x22,0x22,0x22,0x22,0x02,0xFE,0x00,0x00,
    0x00,0xFF,0x00,0x00,0x1F,0x01,0x01,0x7F,0x09,0x11,0x0F,0x40,0x80,0x7F,0x00,0x00,/*"闹",3*/
    0x20,0x10,0x2C,0xE7,0x24,0x24,0x00,0xF0,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00,
    0x01,0x01,0x01,0x7F,0x21,0x11,0x00,0x07,0x02,0x02,0xFF,0x02,0x02,0x07,0x00,0x00,/*"钟",4*/
};

const unsigned char ascii_6X12[][12]={
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/
    0x00,0x00,0xFC,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,/*"!",1*/
    0x00,0x0C,0x02,0x0C,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/
    0x90,0xD0,0xBC,0xD0,0xBC,0x90,0x00,0x03,0x00,0x03,0x00,0x00,/*"#",3*/
    0x18,0x24,0xFE,0x44,0x8C,0x00,0x03,0x02,0x07,0x02,0x01,0x00,/*"$",4*/
    0x18,0x24,0xD8,0xB0,0x4C,0x80,0x00,0x03,0x00,0x01,0x02,0x01,/*"%",5*/
    0xC0,0x38,0xE4,0x38,0xE0,0x00,0x01,0x02,0x02,0x01,0x02,0x02,/*"&",6*/
    0x08,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/
    0x00,0x00,0x00,0xF8,0x04,0x02,0x00,0x00,0x00,0x01,0x02,0x04,/*"(",8*/
    0x00,0x02,0x04,0xF8,0x00,0x00,0x00,0x04,0x02,0x01,0x00,0x00,/*")",9*/
    0x90,0x60,0xF8,0x60,0x90,0x00,0x00,0x00,0x01,0x00,0x00,0x00,/*"*",10*/
    0x20,0x20,0xFC,0x20,0x20,0x00,0x00,0x00,0x01,0x00,0x00,0x00,/*"+",11*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x06,0x00,0x00,0x00,0x00,/*",",12*/
    0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,/*".",14*/
    0x00,0x80,0x60,0x1C,0x02,0x00,0x04,0x03,0x00,0x00,0x00,0x00,/*"/",15*/
    0xF8,0x04,0x04,0x04,0xF8,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"0",16*/
    0x00,0x08,0xFC,0x00,0x00,0x00,0x00,0x02,0x03,0x02,0x00,0x00,/*"1",17*/
    0x18,0x84,0x44,0x24,0x18,0x00,0x03,0x02,0x02,0x02,0x02,0x00,/*"2",18*/
    0x08,0x04,0x24,0x24,0xD8,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"3",19*/
    0x40,0xB0,0x88,0xFC,0x80,0x00,0x00,0x00,0x00,0x03,0x02,0x00,/*"4",20*/
    0x3C,0x24,0x24,0x24,0xC4,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"5",21*/
    0xF8,0x24,0x24,0x2C,0xC0,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"6",22*/
    0x0C,0x04,0xE4,0x1C,0x04,0x00,0x00,0x00,0x03,0x00,0x00,0x00,/*"7",23*/
    0xD8,0x24,0x24,0x24,0xD8,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"8",24*/
    0x38,0x44,0x44,0x44,0xF8,0x00,0x00,0x03,0x02,0x02,0x01,0x00,/*"9",25*/
    0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,/*":",26*/
    0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,/*";",27*/
    0x00,0x20,0x50,0x88,0x04,0x02,0x00,0x00,0x00,0x00,0x01,0x02,/*"<",28*/
    0x90,0x90,0x90,0x90,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"=",29*/
    0x00,0x02,0x04,0x88,0x50,0x20,0x00,0x02,0x01,0x00,0x00,0x00,/*">",30*/
    0x18,0x04,0xC4,0x24,0x18,0x00,0x00,0x00,0x02,0x00,0x00,0x00,/*"?",31*/
    0xF8,0x04,0xE4,0x94,0xF8,0x00,0x01,0x02,0x02,0x02,0x02,0x00,/*"@",32*/
    0x00,0xE0,0x9C,0xF0,0x80,0x00,0x02,0x03,0x00,0x00,0x03,0x02,/*"A",33*/
    0x04,0xFC,0x24,0x24,0xD8,0x00,0x02,0x03,0x02,0x02,0x01,0x00,/*"B",34*/
    0xF8,0x04,0x04,0x04,0x0C,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"C",35*/
    0x04,0xFC,0x04,0x04,0xF8,0x00,0x02,0x03,0x02,0x02,0x01,0x00,/*"D",36*/
    0x04,0xFC,0x24,0x74,0x0C,0x00,0x02,0x03,0x02,0x02,0x03,0x00,/*"E",37*/
    0x04,0xFC,0x24,0x74,0x0C,0x00,0x02,0x03,0x02,0x00,0x00,0x00,/*"F",38*/
    0xF0,0x08,0x04,0x44,0xCC,0x40,0x00,0x01,0x02,0x02,0x01,0x00,/*"G",39*/
    0x04,0xFC,0x20,0x20,0xFC,0x04,0x02,0x03,0x00,0x00,0x03,0x02,/*"H",40*/
    0x04,0x04,0xFC,0x04,0x04,0x00,0x02,0x02,0x03,0x02,0x02,0x00,/*"I",41*/
    0x00,0x04,0x04,0xFC,0x04,0x04,0x06,0x04,0x04,0x03,0x00,0x00,/*"J",42*/
    0x04,0xFC,0x24,0xD0,0x0C,0x04,0x02,0x03,0x02,0x00,0x03,0x02,/*"K",43*/
    0x04,0xFC,0x04,0x00,0x00,0x00,0x02,0x03,0x02,0x02,0x02,0x03,/*"L",44*/
    0xFC,0x3C,0xC0,0x3C,0xFC,0x00,0x03,0x00,0x03,0x00,0x03,0x00,/*"M",45*/
    0x04,0xFC,0x30,0xC4,0xFC,0x04,0x02,0x03,0x02,0x00,0x03,0x00,/*"N",46*/
    0xF8,0x04,0x04,0x04,0xF8,0x00,0x01,0x02,0x02,0x02,0x01,0x00,/*"O",47*/
    0x04,0xFC,0x24,0x24,0x18,0x00,0x02,0x03,0x02,0x00,0x00,0x00,/*"P",48*/
    0xF8,0x84,0x84,0x04,0xF8,0x00,0x01,0x02,0x02,0x07,0x05,0x00,/*"Q",49*/
    0x04,0xFC,0x24,0x64,0x98,0x00,0x02,0x03,0x02,0x00,0x03,0x02,/*"R",50*/
    0x18,0x24,0x24,0x44,0x8C,0x00,0x03,0x02,0x02,0x02,0x01,0x00,/*"S",51*/
    0x0C,0x04,0xFC,0x04,0x0C,0x00,0x00,0x02,0x03,0x02,0x00,0x00,/*"T",52*/
    0x04,0xFC,0x00,0x00,0xFC,0x04,0x00,0x01,0x02,0x02,0x01,0x00,/*"U",53*/
    0x04,0x7C,0x80,0xE0,0x1C,0x04,0x00,0x00,0x03,0x00,0x00,0x00,/*"V",54*/
    0x1C,0xE0,0x3C,0xE0,0x1C,0x00,0x00,0x03,0x00,0x03,0x00,0x00,/*"W",55*/
    0x04,0x9C,0x60,0x9C,0x04,0x00,0x02,0x03,0x00,0x03,0x02,0x00,/*"X",56*/
    0x04,0x1C,0xE0,0x1C,0x04,0x00,0x00,0x02,0x03,0x02,0x00,0x00,/*"Y",57*/
    0x0C,0x84,0x64,0x1C,0x04,0x00,0x02,0x03,0x02,0x02,0x03,0x00,/*"Z",58*/
    0x00,0x00,0xFE,0x02,0x02,0x00,0x00,0x00,0x07,0x04,0x04,0x00,/*"[",59*/
    0x00,0x0E,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x00,/*"\",60*/
    0x00,0x02,0x02,0xFE,0x00,0x00,0x00,0x04,0x04,0x07,0x00,0x00,/*"]",61*/
    0x00,0x04,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,/*"_",63*/
    0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/
    0x00,0x40,0xA0,0xA0,0xC0,0x00,0x00,0x01,0x02,0x02,0x03,0x02,/*"a",65*/
    0x04,0xFC,0x20,0x20,0xC0,0x00,0x00,0x03,0x02,0x02,0x01,0x00,/*"b",66*/
    0x00,0xC0,0x20,0x20,0x60,0x00,0x00,0x01,0x02,0x02,0x02,0x00,/*"c",67*/
    0x00,0xC0,0x20,0x24,0xFC,0x00,0x00,0x01,0x02,0x02,0x03,0x02,/*"d",68*/
    0x00,0xC0,0xA0,0xA0,0xC0,0x00,0x00,0x01,0x02,0x02,0x02,0x00,/*"e",69*/
    0x00,0x20,0xF8,0x24,0x24,0x04,0x00,0x02,0x03,0x02,0x02,0x00,/*"f",70*/
    0x00,0x40,0xA0,0xA0,0x60,0x20,0x00,0x07,0x0A,0x0A,0x0A,0x04,/*"g",71*/
    0x04,0xFC,0x20,0x20,0xC0,0x00,0x02,0x03,0x02,0x00,0x03,0x02,/*"h",72*/
    0x00,0x20,0xE4,0x00,0x00,0x00,0x00,0x02,0x03,0x02,0x00,0x00,/*"i",73*/
    0x00,0x00,0x20,0xE4,0x00,0x00,0x08,0x08,0x08,0x07,0x00,0x00,/*"j",74*/
    0x04,0xFC,0x80,0xE0,0x20,0x20,0x02,0x03,0x02,0x00,0x03,0x02,/*"k",75*/
    0x04,0x04,0xFC,0x00,0x00,0x00,0x02,0x02,0x03,0x02,0x02,0x00,/*"l",76*/
    0xE0,0x20,0xE0,0x20,0xC0,0x00,0x03,0x00,0x03,0x00,0x03,0x00,/*"m",77*/
    0x20,0xE0,0x20,0x20,0xC0,0x00,0x02,0x03,0x02,0x00,0x03,0x02,/*"n",78*/
    0x00,0xC0,0x20,0x20,0xC0,0x00,0x00,0x01,0x02,0x02,0x01,0x00,/*"o",79*/
    0x20,0xE0,0x20,0x20,0xC0,0x00,0x08,0x0F,0x0A,0x02,0x01,0x00,/*"p",80*/
    0x00,0xC0,0x20,0x20,0xE0,0x00,0x00,0x01,0x02,0x0A,0x0F,0x08,/*"q",81*/
    0x20,0xE0,0x40,0x20,0x20,0x00,0x02,0x03,0x02,0x00,0x00,0x00,/*"r",82*/
    0x00,0x60,0xA0,0xA0,0x20,0x00,0x00,0x02,0x02,0x02,0x03,0x00,/*"s",83*/
    0x00,0x20,0xF8,0x20,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x00,/*"t",84*/
    0x20,0xE0,0x00,0x20,0xE0,0x00,0x00,0x01,0x02,0x02,0x03,0x02,/*"u",85*/
    0x20,0xE0,0x20,0x80,0x60,0x20,0x00,0x00,0x03,0x01,0x00,0x00,/*"v",86*/
    0x60,0x80,0xE0,0x80,0x60,0x00,0x00,0x03,0x00,0x03,0x00,0x00,/*"w",87*/
    0x20,0x60,0x80,0x60,0x20,0x00,0x02,0x03,0x00,0x03,0x02,0x00,/*"x",88*/
    0x20,0xE0,0x20,0x80,0x60,0x20,0x08,0x08,0x07,0x01,0x00,0x00,/*"y",89*/
    0x00,0x20,0xA0,0x60,0x20,0x00,0x00,0x02,0x03,0x02,0x02,0x00,/*"z",90*/
    0x00,0x00,0x20,0xDE,0x02,0x00,0x00,0x00,0x00,0x07,0x04,0x00,/*"{",91*/
    0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x0F,0x00,0x00,/*"|",92*/
    0x00,0x02,0xDE,0x20,0x00,0x00,0x00,0x04,0x07,0x00,0x00,0x00,/*"}",93*/
    0x02,0x01,0x02,0x04,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/
};

//16*16 ASCII字符集点阵
const unsigned char ascii_8X16[][16]=      
{
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
    0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
    0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
    0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
    0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
    0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
    0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
    0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
    0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
    0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
    0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
    0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
    0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
    0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
    0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
    0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
    0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
    0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
    0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
    0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
    0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
    0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
    0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
    0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
    0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
    0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
    0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
    0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
    0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
    0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
    0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
    0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
    0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
    0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
    0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
    0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
    0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
    0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
    0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
    0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
    0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
    0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
    0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
    0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
    0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
    0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
    0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
    0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
    0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
    0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
    0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
    0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
    0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
    0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
    0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
    0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
    0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
    0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
    0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
    0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
    0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
    0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
    0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
    0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
    0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
    0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
    0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
    0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
    0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
    0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
    0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
    0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
    0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
    0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
    0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
    0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
    0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
    0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
    0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
    0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
    0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
    0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
    0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
    0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
    0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
    0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
    0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
    0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
    0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
    0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};

//16*16 ASCII字符集点阵
const unsigned char ascii_12X24[][36]=
{
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*" ",0*/
    0x00,0x00,0x00,0x00,0x00,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x00,0x00,0x00,0x00,/*"!",1*/
    0x00,0x00,0x80,0x60,0x30,0x1C,0x8C,0x60,0x30,0x1C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*""",2*/
    0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0x86,0xE6,0x9F,0x86,0x86,0x86,0x86,0xE6,0x9F,0x86,0x00,0x00,0x01,0x1F,0x01,0x01,0x01,0x01,0x01,0x1F,0x01,0x01,0x00,/*"#",3*/
    0x00,0x00,0x80,0xC0,0x60,0x20,0xF8,0x20,0xE0,0xC0,0x00,0x00,0x00,0x00,0x03,0x07,0x0C,0x18,0xFF,0x70,0xE1,0x81,0x00,0x00,0x00,0x00,0x07,0x0F,0x10,0x10,0x7F,0x10,0x0F,0x07,0x00,0x00,/*"$",4*/
    0x80,0x60,0x20,0x60,0x80,0x00,0x00,0x00,0xE0,0x20,0x00,0x00,0x0F,0x30,0x20,0x30,0x9F,0x70,0xDC,0x37,0x10,0x30,0xC0,0x00,0x00,0x00,0x10,0x0E,0x03,0x00,0x07,0x18,0x10,0x18,0x07,0x00,/*"%",5*/
    0x00,0x00,0xC0,0x20,0x20,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0x1F,0x38,0xE8,0x87,0x03,0xC4,0x3C,0x04,0x00,0x00,0x07,0x0F,0x18,0x10,0x10,0x0B,0x07,0x0D,0x10,0x10,0x08,0x00,/*"&",6*/
    0x00,0x80,0x8C,0x4C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"'",7*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0x30,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x18,0x20,0x40,0x00,/*"(",8*/
    0x00,0x04,0x08,0x30,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x0F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,/*")",9*/
    0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x66,0x66,0x3C,0x18,0xFF,0x18,0x3C,0x66,0x66,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,/*"*",10*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,/*"+",11*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x8C,0x4C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*",",12*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"-",13*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*".",14*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x38,0x0C,0x00,0x00,0x00,0x00,0x00,0x80,0x70,0x1C,0x03,0x00,0x00,0x00,0x00,0x00,0x60,0x38,0x0E,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"/",15*/
    0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x01,0xFF,0xFE,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x18,0x0E,0x07,0x01,0x00,/*"0",16*/
    0x00,0x00,0x80,0x80,0x80,0xC0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,/*"1",17*/
    0x00,0x80,0x40,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0x03,0x03,0x00,0x80,0x40,0x20,0x38,0x1F,0x07,0x00,0x00,0x00,0x1C,0x1A,0x19,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,/*"2",18*/
    0x00,0x80,0xC0,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0x00,0x03,0x03,0x00,0x10,0x10,0x18,0x2F,0xE7,0x80,0x00,0x00,0x00,0x07,0x0F,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00,0x00,/*"3",19*/
    0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0xF0,0x00,0x00,0x00,0x00,0xC0,0xB0,0x88,0x86,0x81,0x80,0xFF,0xFF,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,/*"4",20*/
    0x00,0x00,0xE0,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x3F,0x10,0x08,0x08,0x08,0x18,0xF0,0xE0,0x00,0x00,0x00,0x07,0x0B,0x10,0x10,0x10,0x10,0x1C,0x0F,0x03,0x00,0x00,/*"5",21*/
    0x00,0x00,0x80,0xC0,0x40,0x20,0x20,0x20,0xE0,0xC0,0x00,0x00,0x00,0xFC,0xFF,0x21,0x10,0x08,0x08,0x08,0x18,0xF0,0xE0,0x00,0x00,0x01,0x07,0x0C,0x18,0x10,0x10,0x10,0x08,0x0F,0x03,0x00,/*"6",22*/
    0x00,0x00,0xC0,0xE0,0x60,0x60,0x60,0x60,0x60,0xE0,0x60,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0xE0,0x18,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,/*"7",23*/
    0x00,0x80,0xC0,0x60,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x87,0xEF,0x2C,0x18,0x18,0x30,0x30,0x68,0xCF,0x83,0x00,0x00,0x07,0x0F,0x08,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00,/*"8",24*/
    0x00,0x00,0xC0,0xC0,0x20,0x20,0x20,0x20,0xC0,0x80,0x00,0x00,0x00,0x1F,0x3F,0x60,0x40,0x40,0x40,0x20,0x10,0xFF,0xFE,0x00,0x00,0x00,0x0C,0x1C,0x10,0x10,0x10,0x08,0x0F,0x03,0x00,0x00,/*"9",25*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x00,0x00,0x00,0x00,/*":",26*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x38,0x00,0x00,0x00,0x00,0x00,/*";",27*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0x10,0x28,0x44,0x82,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x00,/*"<",28*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"=",29*/
    0x00,0x00,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x82,0x44,0x28,0x10,0x00,0x00,0x00,0x10,0x08,0x04,0x02,0x01,0x00,0x00,0x00,0x00,0x00,/*">",30*/
    0x00,0xC0,0x20,0x20,0x10,0x10,0x10,0x10,0x30,0xE0,0xC0,0x00,0x00,0x03,0x03,0x00,0x00,0xF0,0x10,0x08,0x0C,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x1C,0x00,0x00,0x00,0x00,0x00,/*"?",31*/
    0x00,0x00,0x00,0xC0,0x40,0x60,0x20,0x20,0x20,0x40,0xC0,0x00,0x00,0xFC,0xFF,0x01,0xF0,0x0E,0x03,0xC1,0xFE,0x03,0x80,0x7F,0x00,0x01,0x07,0x0E,0x08,0x11,0x11,0x10,0x11,0x09,0x04,0x02,/*"@",32*/
    0x00,0x00,0x00,0x00,0x80,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7C,0x43,0x40,0x47,0x7F,0xF8,0x80,0x00,0x00,0x10,0x18,0x1F,0x10,0x00,0x00,0x00,0x00,0x13,0x1F,0x1C,0x10,/*"A",33*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,0x18,0x2F,0xE7,0x80,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00,/*"B",34*/
    0x00,0x00,0x80,0xC0,0x40,0x20,0x20,0x20,0x20,0x60,0xE0,0x00,0x00,0xFC,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x10,0x08,0x04,0x03,0x00,/*"C",35*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x40,0xC0,0x80,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x01,0xFF,0xFE,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x18,0x08,0x0E,0x07,0x01,0x00,/*"D",36*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0x60,0x80,0x00,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x06,0x00,/*"E",37*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x20,0x60,0x60,0x80,0x00,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,0x01,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"F",38*/
    0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x20,0x40,0xE0,0x00,0x00,0x00,0xFC,0xFF,0x01,0x00,0x00,0x40,0x40,0xC0,0xC1,0x40,0x40,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x10,0x0F,0x0F,0x00,0x00,/*"G",39*/
    0x20,0xE0,0xE0,0x20,0x00,0x00,0x00,0x00,0x20,0xE0,0xE0,0x20,0x00,0xFF,0xFF,0x10,0x10,0x10,0x10,0x10,0x10,0xFF,0xFF,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,/*"H",40*/
    0x00,0x00,0x20,0x20,0x20,0xE0,0xE0,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,/*"I",41*/
    0x00,0x00,0x00,0x00,0x20,0x20,0x20,0xE0,0xE0,0x20,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x60,0xE0,0x80,0x80,0x80,0xC0,0x7F,0x3F,0x00,0x00,0x00,/*"J",42*/
    0x20,0xE0,0xE0,0x20,0x00,0x00,0x20,0xA0,0x60,0x20,0x20,0x00,0x00,0xFF,0xFF,0x30,0x18,0x7C,0xE3,0xC0,0x00,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x01,0x13,0x1F,0x1C,0x18,0x10,/*"K",43*/
    0x20,0xE0,0xE0,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x10,0x10,0x10,0x10,0x10,0x18,0x06,0x00,/*"L",44*/
    0x20,0xE0,0xE0,0xE0,0x00,0x00,0x00,0x00,0xE0,0xE0,0xE0,0x20,0x00,0xFF,0x01,0x3F,0xFE,0xC0,0xE0,0x1E,0x01,0xFF,0xFF,0x00,0x10,0x1F,0x10,0x00,0x03,0x1F,0x03,0x00,0x10,0x1F,0x1F,0x10,/*"M",45*/
    0x20,0xE0,0xE0,0xC0,0x00,0x00,0x00,0x00,0x00,0x20,0xE0,0x20,0x00,0xFF,0x00,0x03,0x07,0x1C,0x78,0xE0,0x80,0x00,0xFF,0x00,0x10,0x1F,0x10,0x00,0x00,0x00,0x00,0x00,0x03,0x0F,0x1F,0x00,/*"N",46*/
    0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFE,0x00,0x00,0x01,0x07,0x0E,0x18,0x10,0x10,0x18,0x0C,0x07,0x01,0x00,/*"O",47*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0xFF,0xFF,0x20,0x20,0x20,0x20,0x20,0x30,0x1F,0x0F,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"P",48*/
    0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0x00,0xFE,0xFF,0x01,0x00,0x00,0x00,0x00,0x00,0xFF,0xFE,0x00,0x00,0x01,0x07,0x0E,0x11,0x11,0x13,0x3C,0x7C,0x67,0x21,0x00,/*"Q",49*/
    0x20,0xE0,0xE0,0x20,0x20,0x20,0x20,0x20,0x60,0xC0,0x80,0x00,0x00,0xFF,0xFF,0x10,0x10,0x30,0xF0,0xD0,0x08,0x0F,0x07,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x00,0x03,0x0F,0x1C,0x10,0x10,/*"R",50*/
    0x00,0x80,0xC0,0x60,0x20,0x20,0x20,0x20,0x40,0x40,0xE0,0x00,0x00,0x07,0x0F,0x0C,0x18,0x18,0x30,0x30,0x60,0xE0,0x81,0x00,0x00,0x1F,0x0C,0x08,0x10,0x10,0x10,0x10,0x18,0x0F,0x07,0x00,/*"S",51*/
    0x80,0x60,0x20,0x20,0x20,0xE0,0xE0,0x20,0x20,0x20,0x60,0x80,0x01,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x00,0x00,/*"T",52*/
    0x20,0xE0,0xE0,0x20,0x00,0x00,0x00,0x00,0x00,0x20,0xE0,0x20,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x07,0x0F,0x18,0x10,0x10,0x10,0x10,0x10,0x08,0x07,0x00,/*"U",53*/
    0x20,0x60,0xE0,0xE0,0x20,0x00,0x00,0x00,0x20,0xE0,0x60,0x20,0x00,0x00,0x07,0x7F,0xF8,0x80,0x00,0x80,0x7C,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1F,0x1C,0x07,0x00,0x00,0x00,0x00,/*"V",54*/
    0x20,0xE0,0xE0,0x20,0x00,0xE0,0xE0,0x20,0x00,0x20,0xE0,0x20,0x00,0x07,0xFF,0xF8,0xE0,0x1F,0xFF,0xFC,0xE0,0x1F,0x00,0x00,0x00,0x00,0x03,0x1F,0x03,0x00,0x01,0x1F,0x03,0x00,0x00,0x00,/*"W",55*/
    0x00,0x20,0x60,0xE0,0xA0,0x00,0x00,0x20,0xE0,0x60,0x20,0x00,0x00,0x00,0x00,0x03,0x8F,0x7C,0xF8,0xC6,0x01,0x00,0x00,0x00,0x00,0x10,0x18,0x1E,0x13,0x00,0x01,0x17,0x1F,0x18,0x10,0x00,/*"X",56*/
    0x20,0x60,0xE0,0xE0,0x20,0x00,0x00,0x00,0x20,0xE0,0x60,0x20,0x00,0x00,0x01,0x07,0x3E,0xF8,0xE0,0x18,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x00,0x00,0x00,/*"Y",57*/
    0x00,0x80,0x60,0x20,0x20,0x20,0x20,0xA0,0xE0,0xE0,0x20,0x00,0x00,0x00,0x00,0x00,0xC0,0xF0,0x3E,0x0F,0x03,0x00,0x00,0x00,0x00,0x10,0x1C,0x1F,0x17,0x10,0x10,0x10,0x10,0x18,0x06,0x00,/*"Z",58*/
    0x00,0x00,0x00,0x00,0x00,0xFC,0x04,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x40,0x40,0x00,/*"[",59*/
    0x00,0x00,0x10,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x1C,0x60,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x70,0x80,0x00,/*"\",60*/
    0x00,0x00,0x04,0x04,0x04,0x04,0x04,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,0x00,/*"]",61*/
    0x00,0x00,0x00,0x10,0x08,0x0C,0x04,0x0C,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"^",62*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,/*"_",63*/
    0x00,0x00,0x00,0x04,0x04,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"`",64*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x98,0xD8,0x44,0x64,0x24,0x24,0xFC,0xF8,0x00,0x00,0x00,0x0F,0x1F,0x18,0x10,0x10,0x10,0x08,0x1F,0x1F,0x10,0x18,/*"a",65*/
    0x00,0x20,0xE0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x18,0x08,0x04,0x04,0x0C,0xF8,0xF0,0x00,0x00,0x00,0x1F,0x0F,0x18,0x10,0x10,0x10,0x18,0x0F,0x03,0x00,/*"b",66*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xF8,0x18,0x04,0x04,0x04,0x3C,0x38,0x00,0x00,0x00,0x00,0x03,0x0F,0x0C,0x10,0x10,0x10,0x10,0x08,0x06,0x00,0x00,/*"c",67*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0xE0,0xF0,0x00,0x00,0x00,0xE0,0xF8,0x1C,0x04,0x04,0x04,0x08,0xFF,0xFF,0x00,0x00,0x00,0x03,0x0F,0x18,0x10,0x10,0x10,0x08,0x1F,0x0F,0x08,0x00,/*"d",68*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xF8,0x48,0x44,0x44,0x44,0x4C,0x78,0x70,0x00,0x00,0x00,0x03,0x0F,0x0C,0x18,0x10,0x10,0x10,0x08,0x04,0x00,/*"e",69*/
    0x00,0x00,0x00,0x00,0x80,0xC0,0x60,0x20,0x20,0xE0,0xC0,0x00,0x00,0x04,0x04,0x04,0xFF,0xFF,0x04,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,0x00,/*"f",70*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0xF8,0x8C,0x04,0x04,0x8C,0xF8,0x74,0x04,0x0C,0x00,0x70,0x76,0xCF,0x8D,0x8D,0x8D,0x89,0xC8,0x78,0x70,0x00,/*"g",71*/
    0x00,0x20,0xE0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x08,0x04,0x04,0x04,0xFC,0xF8,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,/*"h",72*/
    0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,/*"i",73*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0xFC,0xFC,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0x80,0x80,0xC0,0x7F,0x3F,0x00,0x00,0x00,/*"j",74*/
    0x00,0x20,0xE0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x80,0xC0,0xF4,0x1C,0x04,0x04,0x00,0x00,0x00,0x10,0x1F,0x1F,0x11,0x00,0x03,0x1F,0x1C,0x10,0x10,0x00,/*"k",75*/
    0x00,0x00,0x20,0x20,0x20,0xE0,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,/*"l",76*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0xFC,0x08,0x04,0xFC,0xFC,0x08,0x04,0xFC,0xFC,0x00,0x10,0x1F,0x1F,0x10,0x00,0x1F,0x1F,0x10,0x00,0x1F,0x1F,0x10,/*"m",77*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0xFC,0x08,0x08,0x04,0x04,0xFC,0xF8,0x00,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,0x00,0x10,0x1F,0x1F,0x10,0x00,/*"n",78*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xF0,0x18,0x0C,0x04,0x04,0x0C,0x18,0xF0,0xE0,0x00,0x00,0x03,0x0F,0x0C,0x10,0x10,0x10,0x10,0x0C,0x0F,0x03,0x00,/*"o",79*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0xFC,0x08,0x04,0x04,0x04,0x0C,0xF8,0xF0,0x00,0x00,0x80,0xFF,0xFF,0x88,0x90,0x10,0x10,0x1C,0x0F,0x03,0x00,/*"p",80*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xF8,0x1C,0x04,0x04,0x04,0x08,0xF8,0xFC,0x00,0x00,0x00,0x03,0x0F,0x18,0x10,0x10,0x90,0x88,0xFF,0xFF,0x80,0x00,/*"q",81*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0xFC,0xFC,0x10,0x08,0x04,0x04,0x0C,0x0C,0x00,0x10,0x10,0x10,0x1F,0x1F,0x10,0x10,0x10,0x00,0x00,0x00,0x00,/*"r",82*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x78,0xCC,0xC4,0x84,0x84,0x84,0x0C,0x1C,0x00,0x00,0x00,0x1E,0x18,0x10,0x10,0x10,0x11,0x19,0x0F,0x06,0x00,/*"s",83*/
    0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0xFF,0xFF,0x04,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x1F,0x10,0x10,0x10,0x0C,0x00,0x00,/*"t",84*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xFC,0xFE,0x00,0x00,0x00,0x04,0xFC,0xFE,0x00,0x00,0x00,0x00,0x0F,0x1F,0x18,0x10,0x10,0x08,0x1F,0x0F,0x08,0x00,/*"u",85*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0C,0x3C,0xFC,0xC4,0x00,0x00,0xC4,0x3C,0x0C,0x04,0x00,0x00,0x00,0x00,0x01,0x0F,0x1E,0x0E,0x01,0x00,0x00,0x00,/*"v",86*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x3C,0xFC,0xC4,0x00,0xE4,0x7C,0xFC,0x84,0x80,0x7C,0x04,0x00,0x00,0x07,0x1F,0x07,0x00,0x00,0x07,0x1F,0x07,0x00,0x00,/*"w",87*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x1C,0x7C,0xE4,0xC0,0x34,0x1C,0x04,0x04,0x00,0x00,0x10,0x10,0x1C,0x16,0x01,0x13,0x1F,0x1C,0x18,0x10,0x00,/*"x",88*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x0C,0x3C,0xFC,0xC4,0x00,0xC4,0x3C,0x04,0x04,0x00,0x00,0x00,0xC0,0x80,0xC1,0x37,0x0E,0x01,0x00,0x00,0x00,0x00,/*"y",89*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x04,0x04,0xC4,0xF4,0x7C,0x1C,0x04,0x00,0x00,0x00,0x00,0x10,0x1C,0x1F,0x17,0x11,0x10,0x10,0x18,0x0E,0x00,/*"z",90*/
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x0C,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x28,0xEF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x60,0x40,0x00,0x00,/*"{",91*/
    0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,/*"|",92*/
    0x00,0x00,0x04,0x0C,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEF,0x28,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x60,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"}",93*/
    0x00,0x18,0x06,0x02,0x02,0x04,0x08,0x10,0x20,0x20,0x30,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"~",94*/    
};


#endif

210 低功耗及电源结构介绍

(1)低功耗(low power mode),适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。
(2)STM32电源系统结构:VDDA供电区域(A为模拟量),VDD供电区域,1.8V供电区域,后备供电区域;

211 睡眠,停机,待机模式特点

(1)四种工作模式:运行、睡眠、停止和待机,上电后默认是在运行模式,睡眠、停止和待机这3种为低功耗模式,功耗等级由高到低;
(2)睡眠模式(sleep mode):CPU停止工作,但所有外设(如ADC、通信接口等)仍然运行,时钟继续运转。
(3)停机模式(stop mode):CPU和核心外围设备的时钟会停止,但部分唤醒源(如外部中断和某些定时器)仍然运行。
(4)待机模式(standby mode):CPU、外围设备和时钟都被关闭,只保留唤醒逻辑和备份寄存器。

212 低功耗进入及唤醒条件

(1)低功耗进入:睡眠模式(WFI/WFE),停机模式(WFI/WFE+SLEEPDEEP+PDDS+LPDS),待机模式((WFI/WFE+SLEEPDEEP+PDDS);
注:WFI(wait for interrupt),WFE(wait for EVENT)
(2)低功耗唤醒条件:睡眠模式(任一中断/唤醒事件),停机模式(任一外部中断(在外部中断寄存器中设置)),待机模式(WKUP引脚的上升沿,RTC闹钟事件,NRST引脚上的外部复位,IWDG复位);

213 低功耗寄存器及库函数介绍

(1)寄存器:电源控制寄存器(PWR_CR)-PDDS,LPDS,电源控制/状态寄存器(PWR_CSR)-EWUP,WUF,System control register (SCB_SCR)-SLEEPDEEP,SLEEPONEXIT。
(2)库函数:HAL_PWR_EnterSLEEPMode(),HAL_PWR_EnterSTANDBYMode(),HAL_PWR_EnterSTOPMode(),HAL_PWR_DisableWakeUpPin();

214 低功耗实验

(1)实验目的:
1. 按下按键 2 ,进入低功耗模式(睡眠、停机、待机);
2. 按下按键 1 ,退出低功耗模式;
3. 正常模式下,LED1 闪烁;进入停机模式,LED2 长亮,退出停机模式则 LED2 熄灭。
(2)添加key模块(保留key2键),编写低功耗初始化函数lpwr_init(),进入睡眠模式函数lpwr_enter_sleep(),进入停机模式lpwr_enter_stop(),进入待机模式lpwr_enter_standby();-(57. 低功耗实验-mian.c,lpwr.h,key.c,lpwr.h,key.h)-待测试
注:1.从停机模式唤醒,HSI RC振荡器选为系统时钟仅8MHZ,需要重新配置系统时钟72MHZ,stm32_clock_init(RCC_PLL_MUL9);
2.进入睡眠模式和停机模式前,需先暂停滴答定时器,防止由滴答定时器中断造成的唤醒;
3.待机模式下需关闭电压调节器,若用WKUP引脚唤醒的话,需使能WAKEUP引脚的唤醒功能,并清除唤醒标记。
4.停机模式唤醒后从"进入停机模式函数"后开始执行,待机模式唤醒后从"main.c函数"开头开始执行;

/*
-------------------------------------------------------------------------
mian.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "key.h"
#include "lpwr.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    key_init();
    lpwr_init();
    printf("hello world!\r\n");
    uint8_t i = 0;
    while(1)
    { 
        if(key_scan() == 2)
        {
            lpwr_enter_sleep();
            lpwr_enter_stop();
            lpwr_enter_standby();
        }
        if(i%20 == 0)
            led1_toggle();
        i++;
        delay_ms(10);
    }
}


/*
-------------------------------------------------------------------------
lpwr.h:
-------------------------------------------------------------------------
*/
#include "lpwr.h"
#include "led.h"

//低功耗初始化函数lpwr_init()
void lpwr_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOB时钟
    //调用GPIO初始化函数
//    HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)

    gpio_initstruct.Pin = GPIO_PIN_0;
    gpio_initstruct.Mode = GPIO_MODE_IT_RISING; // 上升沿中断
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
    HAL_NVIC_SetPriority(EXTI0_IRQn,2,2);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

//中断处理函数
void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);   
}    

//进入睡眠模式函数lpwr_enter_sleep
void lpwr_enter_sleep(void)
{
    HAL_SuspendTick();暂停滴答定时器,防止由滴答定时器中断造成的唤醒
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
}    

//进入停机模式lpwr_enter_stop()
void lpwr_enter_stop(void)
{
    HAL_SuspendTick();
    led2_on();
    HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
    led2_off();
    stm32_clock_init(RCC_PLL_MUL9); //从停机模式唤醒,需要重新配置系统时钟

}    
//进入待机模式lpwr_enter_standby()
void lpwr_enter_standby(void)
{
    //使能电源时钟(关闭电压调节器)
    __HAL_RCC_PWR_CLK_ENABLE();
    //使能WAKEUP引脚的唤醒功能
    HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
    //清除唤醒标记,否则将持续保持唤醒状态
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
    HAL_PWR_EnterSTANDBYMode();
    led2_on();
}    

/*
-------------------------------------------------------------------------
key.c:
-------------------------------------------------------------------------
*/
#include "key.h"
#include "sys.h"
#include "delay.h"

//初始化GPIO
void key_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    //调用GPIO初始化函数
    // HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
    gpio_initstruct.Pin =  GPIO_PIN_1; // LED1及LED2对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_INPUT; // 输入
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}

//按键扫描函数
uint8_t key_scan(void){
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET);
            //返回按键值
            return 2;
        }     
    }
    //返回默认值
    return 0;
}

/*
-------------------------------------------------------------------------
lpwr.h:
-------------------------------------------------------------------------
*/
#ifndef __LPWR_H__
#define __LPWR_H__
#include "sys.h"
void lpwr_init(void);
void lpwr_enter_sleep(void);
void lpwr_enter_stop(void);
void lpwr_enter_standby(void);
#endif

/*
-------------------------------------------------------------------------
key.h:
-------------------------------------------------------------------------
*/
#ifndef __KEY_H__
#define __KEY_H__
#include "sys.h"
void key_init(void);
uint8_t key_scan(void);
#endif

215 CAN介绍

(1)CAN协议,全称为Controller Area Network(控制器局域网络),是一种基于差分信号的异步串行通信协议,采用双绞线作为传输介质。
低速CAN(ISO11519)通信速率 10~125Kbps,总线长度可达 1000 米。
高速CAN(ISO11898)通信速率 125Kbps~1Mbps,总线长度 ≤40 米。
特点:多主控制,系统柔软性,通信速度快、距离远,错误检测与恢复,故障封闭功能。

216 CAN物理层介绍

(1)CAN网络通常由CAN控制器(负责处理数据的收发和协议转换)、CAN收发器(负责将控制器的数字信号转换为差分信号进行传输,同时也负责将总线上的差分信号转换为数字信号供控制器处理)和双绞线组成。
(2)高速CAN即闭环CAN总线,低速CAN即开环CAN总线,高速CAN总线两端接了120Ω的终端电阻(主要作用是匹配总线阻抗,提高信号质量,减少回波反射)。
(3)电平标准:高速CAN(显性电平表示逻辑0,通常CAN_H和CAN_L有2V的压差,隐性电平表示逻辑1,通常CAN_H和CAN_L有0V的压差);
低速CAN(显性电平表示逻辑0,通常CAN_H和CAN_L有3V的压差,隐性电平表示逻辑1,通常CAN_H和CAN_L有-1.5V的压差)

217 CAN数据帧详解

(1)CAN帧种类:数据帧(Data Frame),遥控帧(Remote Frame),错误帧(Error Frame),过载帧(Overload Frame),帧间隔(Interframe Space)。
(2)数据帧:数据帧包括必要的帧头、标识符、控制位、数据长度代码、数据域、CRC校验码和应答域等部分。数据帧又分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),主要体现在仲裁段和控制段。
数据帧由7段组成:帧起始(Frame Start),仲裁段(Arbitration Field),控制段(Control Field),数据段(Data Field),CRC段(CRC Field),应答段(ACK Field),帧结束(Frame End)。

218 CAN时序及仲裁机制

(1)CAN总线以"位同步"机制,实现对电平的正确采样,位数据都由四段组成:同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2),每段又由多个位时序Tq组成。采样点位于PBS1 结束处。
(2)CAN总线的时钟同步机制:
1.硬同步-帧的起始位(SOF)同步,
2.软同步-在帧的后续数据位中进行,接收节点检测到数据位的跳变沿不在自身的同步段内,则会通过延长或缩短相位缓冲段的时间来调整自身的位时间,以重新获得同步。
(3)多个单元同时开始发送时要进行仲裁,仲裁机制为:
标识符优先级-(数据帧的起始部分为数据的标识符(ID),标识符的数值越小,优先级越高),
逐位仲裁-(按照标识符的位顺序逐位进行仲裁),
显性电平优先-(显性电平(逻辑0)的优先级高于隐性电平(逻辑1))。

219 CAN控制器及模式介绍

(1)STM32 CAN控制器:STM32的bxCAN,即基本扩展CAN(Basic Extend CAN)。
(2)协议支持(支持CAN协议2.0A和2.0B的主动模式);高波特率(波特率最高可达1兆位/秒);时间触发通信(支持时间触发通信功能);发送功能(3个发送邮箱);接收功能(具有3级深度的2个FIFO(First In First Out,先进先出队列));
(3)CAN控制器的工作模式:初始化模式(禁止报文的接收和发送,可以对CAN控制器的相关寄存器进行配置)、正常模式(可以向总线发送或接收数据)和睡眠模式(CAN控制器的时钟停止,但软件仍然可以访问邮箱寄存器)。
(4)CAN控制器的测试模式有三种:静默模式(CAN控制器可以正常地接收数据帧和远程帧,但只能发出隐性位,而不能真正发送报文)、
环回模式(CAN控制器会把发送的报文当作接收的报文并保存)和环回静默模式(结合了静默模式和环回模式)。

220 CAN控制器框图

(1)CAN控制器框图主要由4部分组成->
CAN控制内核:包含各种控制/状态/配置寄存器,用于配置CAN控制器的模式、波特率等参数。
发送邮箱(Transmit Mailbox):用来缓存待发送的CAN报文。
接收FIFO(First In First Out):缓存接收到的有效CAN报文。
接收过滤器(Receive Filter):筛选接收到的CAN报文,只将符合特定条件的报文保存到接收FIFO中。

(2)有效报文指的是(数据帧直到EOF段的最后一位都没有错误),且通过过滤器组对标识符过滤。
(3)过滤器根据位宽划分:16位(用于标准帧)和32位(用于扩展帧)。
(4)过滤器选择模式可设置:屏蔽位模式(选择出一组符合条件的报文)或标识符列表模式(选择出几个特定ID的报文)

221 CAN控制器位时序

(1)CAN控制器时序分为3段,SYNC_SEG,时间段1(BS1),时间段2(BS2)
(2)波特率=1/正常位时间,正常位时间=1tq+tBS1+tBS2;其中tBS1=tq(TS1[3:0]+1),tBS2=tq*(TS2[2:0]+1),tq=(BRP[9:0]+1)*tPCLK,
这里tq表示1个单元时间,tPCLK=APB时钟周期,TS1[3:0],TS2[2:0],BRP[9:0]在CAN_BTR寄存器中定义;

222 CAN控制器寄存器及库函数介绍

(1)CAN控制器寄存器:CAN控制和状态寄存器(CAN主控制寄存器 (CAN_MCR),CAN发送状态寄存器 (CAN_TSR),CAN接收FIFO 0寄存器 (CAN_RF0R),CAN位时序寄存器 (CAN_BTR) 等),
CAN邮箱寄存器(发送邮箱标识符寄存器 (CAN_TIxR),发送邮箱低字节数据寄存器 (CAN_TDLxR),发送邮箱高字节数据寄存器 (CAN_TDHxR)等),
CAN过滤器寄存器(CAN 过滤器主控寄存器 (CAN_FMR),CAN 过滤器模式寄存器 (CAN_FM1R)等)。
库函数:HAL_CAN_Init(),HAL_CAN_ConfigFilter(),HAL_CAN_Start(),HAL_CAN_AddTxMessage(),HAL_CAN_GetRxMessage(),HAL_CAN_GetTxMailboxesFreeLevel(),HAL_CAN_GetRxFifoFillLevel()等

223-224 CAN收发实验

(1)CAN基本驱动流程:CAN参数初始化(工作模式,波特率,功能设置等)->msp函数初始化(时钟,引脚,中断等)->过滤器设置->发送,接收函数编写->中断服务函数编写
(2)编写can初始化函数can_init(),can的msp初始化函数HAL_CAN_MspInit(),can发送数据函数can_send_data(),can接收数据函数can_receive_data();-(58. CAN收发实验-main.c,can.c,key,c,can.h,key.h)-待测试

/*
-------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "can.h"
#include "key.h"
uint8_t data_send[8] ={0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
uint8_t data_receive[8];
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    can_init();
    key_init();
    printf("hello world!\r\n");
    uint8_t i = 0;
    while(1)
    { 
        if(key_scan() == 1)
        {
            for(i = 0;i < 8;i++)
                data_send[i]++;
                can_send_data(0x12345678,data_send,8);
        }
        can_receive_data(data_receive);
              
    }
}


/*
-------------------------------------------------------------------------
can.c:
-------------------------------------------------------------------------
*/
#include "can.h"
#include "stdio.h"

CAN_HandleTypeDef can_handle ={0};
//can初始化函数can_init()
void can_init(void)
{
    can_handle.Instance = CAN1;
    can_handle.Init.AutoBusOff = DISABLE;
    can_handle.Init.AutoRetransmission = DISABLE;
    can_handle.Init.AutoWakeUp = DISABLE;
    can_handle.Init.Mode = CAN_MODE_NORMAL;//测试时可用CAN_MODE_LOOPBACK
    can_handle.Init.Prescaler = 4;
    can_handle.Init.ReceiveFifoLocked = DISABLE;
    can_handle.Init.SyncJumpWidth =CAN_SJW_1TQ;
    can_handle.Init.TimeSeg1 = CAN_BS1_9TQ;
    can_handle.Init.TimeSeg2 = CAN_BS2_8TQ;
    can_handle.Init.TimeTriggeredMode = DISABLE;
    can_handle.Init.TransmitFifoPriority = DISABLE;
    //HAL_StatusTypeDef HAL_CAN_Init(CAN_HandleTypeDef *hcan)
    HAL_CAN_Init(&can_handle);
    //HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, const CAN_FilterTypeDef *sFilterConfig)
    CAN_FilterTypeDef can_filterconfig = {0};
    can_filterconfig.FilterActivation = CAN_FILTER_ENABLE;
    can_filterconfig.FilterBank = 0;
    can_filterconfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    can_filterconfig.FilterIdHigh = 0;
    can_filterconfig.FilterIdLow = 0;
    can_filterconfig.FilterMaskIdHigh = 0;
    can_filterconfig.FilterMaskIdLow = 0;
    can_filterconfig.FilterMode = CAN_FILTERMODE_IDMASK;
    can_filterconfig.FilterScale = CAN_FILTERSCALE_32BIT;
    can_filterconfig.SlaveStartFilterBank = 14;
    HAL_CAN_ConfigFilter(&can_handle,&can_filterconfig);
    HAL_CAN_Start(&can_handle);
}    

//can的msp初始化函数HAL_CAN_MspInit()
void HAL_CAN_MspInit(CAN_HandleTypeDef *hcan)
{
    __HAL_RCC_CAN1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef gpio_initstruct;
    gpio_initstruct.Pin = GPIO_PIN_11;
    gpio_initstruct.Mode = GPIO_MODE_AF_INPUT; 
    gpio_initstruct.Pull = GPIO_PULLUP;
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
    
    gpio_initstruct.Pin = GPIO_PIN_12;
    gpio_initstruct.Mode = GPIO_MODE_AF_PP;     
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}    

//can发送数据函数can_send_data()
void can_send_data(uint32_t id,uint8_t *buf,uint8_t len)
{
    CAN_TxHeaderTypeDef tx_header = {0};
    uint32_t tx_mail = CAN_TX_MAILBOX0;
    tx_header.DLC = len;
    tx_header.ExtId = id;
    tx_header.IDE = CAN_ID_EXT;
    tx_header.RTR = CAN_RTR_DATA;
    //HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, const CAN_TxHeaderTypeDef *pHeader,const uint8_t aData[], uint32_t *pTxMailbox)
    HAL_CAN_AddTxMessage(&can_handle,&tx_header,buf,&tx_mail);
    while(HAL_CAN_GetTxMailboxesFreeLevel(&can_handle) != 3);
    uint8_t i = 0;
    printf("发送数据:\r\n");
    for(i=0;i<len;i++)
        printf("%X",buf[i]);
    printf("\r\n");
}
//can接收数据函数can_receive_data()
uint8_t can_receive_data(uint8_t *buf)
{
    CAN_RxHeaderTypeDef rx_header ={0};
    if(HAL_CAN_GetRxFifoFillLevel(&can_handle,CAN_RX_FIFO0) == 0)
        return 0;
    //HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[])
    HAL_CAN_GetRxMessage(&can_handle,CAN_RX_FIFO0,&rx_header,buf);
    uint8_t i = 0;
    printf("接收数据:\r\n");
    for(i = 0;i < rx_header.DLC;i++);
        printf("%X",buf[i]);
    printf("\r\n");
    return rx_header.DLC;

}

/*
-------------------------------------------------------------------------
key,c:
-------------------------------------------------------------------------
*/
#include "key.h"
#include "sys.h"
#include "delay.h"

//初始化GPIO
void key_init(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE(); // 使能GPIOB时钟
    //调用GPIO初始化函数
    // HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
    gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1; // LED1及LED2对应的引脚
    gpio_initstruct.Mode = GPIO_MODE_INPUT; // 输入
    gpio_initstruct.Pull = GPIO_PULLUP; // 上拉
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
    HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}

//按键扫描函数
uint8_t key_scan(void){
    //GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);
            //返回按键值
            return 1;
        }       
    }
    //检测按键是否按下
    if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
    {
        //消抖
        delay_ms(10);
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_RESET)
        {
            //如果确实是按下的状态,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET);
            //返回按键值
            return 2;
        }     
    }
    //返回默认值
    return 0;
}

/*
-------------------------------------------------------------------------
can.h:
-------------------------------------------------------------------------
*/
#ifndef __CAN_H__
#define __CAN_H__
#include "sys.h"
void can_init(void);
void can_send_data(uint32_t id,uint8_t *buf,uint8_t len);
uint8_t can_receive_data(uint8_t *buf);
#endif

/*
-------------------------------------------------------------------------
key.h:
-------------------------------------------------------------------------
*/
#ifndef __KEY_H__
#define __KEY_H__
#include "sys.h"
void key_init(void);
uint8_t key_scan(void);
#endif

225 MQTT基本介绍

(1)参考文章:https://www.lxlinux.net/e/stm32/mqtt-turorial.html
(2)MQTT:(Message Queuing Telemetry Transport,消息队列遥测传输)协议,基于TCP/IP协议栈构建的异步通信消息协议,是一种轻量级的、客户端服务端架构的、发布/订阅模式的消息传输协议。
MQTT原理:客户端向一「主题」「发布」消息,服务端处理并推送给「订阅」了该「主题」的其他客户端。
发布与订阅的特点:相互独立(客户端相互独立,彼此没有直接联系),空间分离(客户端只要连接同一个 MQTT 通讯网络,无论是互联网或者局域网都可以通讯),时间异步(客户端的发布与订阅无需同步)。

226 MQTT报文格式介绍

(1)MQTT报文:由固定报头、可变报头、有效载荷三部分组成,其中
固定报头(Fixed header),所有 MQTT 报文有,表示报文类型及报文的分组类标识。
可变报头(Variable header),部分 MQTT 报文有,报文类型决定了可变头是否存在及其具体内容。
有效载荷/消息体(Payload),部分 MQTT 报文有,存放报文的具体内容。
(2)固定报头由消息类型(message type), 标志位(DUP、QoS Level、RET), 剩余长度(Remaining Length))这3部分组成;

227 OneNET基本配置

(1)云平台OneNET配置:OneNET官方网址(https://open.iot.10086.cn) ,新建产品及其下设备后,保存设备详情中的MQTT三元组(设备ID,产品ID,设备密钥)。

228 MQTT报文概述

(1)客户端向服务分别发送"CONNECT报文",“SUBSCRIBE报文”,“UNSUBSCRIBE报文”,“PINGREQ报文”,“PUBLISH报文”,
服务器向客户端分别回复"CONNACK报文",“SUBACK报文”,“UNSUBACK报文”,PINGRESP报文,无需回复。

229 CONNECT报文之固定报头和可变报文

(1)报文实例链接:https://q4p5s568ub.feishu.cn/docx/ECsSdCSGoooQvux7U1xcmGaLnNd?from=from_copylink
(2)CONNECT报文=固定报头+可变报头+有效载荷。
固定包头(2-6字节):(MQTT控制报文类型+用于指定控制报文类型标志位)(1字节)+剩余长度(1-4字节),例:CONNECT 报文固定报头的十六进制是:10 XX
可变报头(10字节):协议名(6字节)+协议级别(1字节)+连接标志(1字节)+保持连接(2字节),例:CONNECT 报文的可变头的十六进制是:00 04 4D 51 54 54 04 C2 00 64

230 CONNECT报文之有效载荷

(1)有效载荷 = 长度+设备 ID + 产品 ID + token
注:token 是在 MQTT 协议中用于服务端与客户端对接的参数。由res+et+key+method+version这些参数组成,经token生成工具生成后转换为16进制。
这里的有效载荷仅适用OneNET,每个平台的MQTT报文基本一致,但是有效载荷会有一点不同。
OneNET 官方的token生成工具官网下载地址:https://open.iot.10086.cn/doc/v5/develop/detail/624,
et 的时间戳可以用这个在线工具转换:https://tool.lu/timestamp/,
可在网络调试助手中通过发送报文来确定报文长度。

231 剩余长度

(1)剩余长度=去掉固定报头报文的长度;
剩余长度是使用变长度编码方案,低7位(第0到6位)用于编码数据,最高有效位(第7位)用于表示是否有更多字节,最大可以使用4个字节。
(2)OneNET服务器地址:mqtts.heclouds.com : 1883

232 CONNACK报文

(1)CONNECT报文=固定报头+可变报头
固定报头(2字节)=(MQTT控制报文类型 + Reserved保留位)(1字节)+剩余长度(1字节);例:20 02。
可变报头(2字节)=连接确认标志(1字节)+连接返回码(1字节);例:00 00。

233 SUBSCRIBE与SUBACK报文

(1)SUBSCRIBE报文=固定报头+可变报头+有效载荷
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:82 XX
可变报头(2字节)=报文标识符(2字节);例:00 0A
有效载荷=长度+主题过滤器(N字节)+服务质量要求(1字节);
注:主题过滤器在OneNet产品开发中的设备开发/Topic管理提取后转16进制
(2)SUBACK报文=固定报头+可变报头+有效载荷
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:90 03
可变报头(2字节)=报文标识符(2字节);例:00 0A
有效载荷(1字节)=返回码(1字节);例:00

234 UNSUBSCRIBE与UNSUBACK报文

(1)UNSUBSCRIBE报文=固定报头+可变报头+有效载荷
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:A2 XX
可变报头(2字节)=报文标识符(2字节);例:00 0B
有效载荷=长度+主题过滤器(N字节);
注:主题过滤器在OneNet产品开发中的设备开发/Topic管理提取后转16进制
(2)UNSUBACK报文=固定报头+可变报头
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:B0 02
可变报头(2字节)=报文标识符(2字节);例:00 0B

235 PUBLISH报文

(1)PUBLISH报文=固定报头+可变报头+有效载荷
固定报头=(MQTT控制报文类型 + DUP+QoS等级+RETAIN)(1字节)+剩余长度(1字节);例:30 XX
可变报头=长度+主题
有效载荷=JSON格式的发布内容
注:主题在OneNet产品开发中的设备开发/Topic管理提取后转16进制

236 PINGREQ和PINGRESP报文

(1)PINGREQ报文=固定报文
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:C0 00
(2)PINGRESP报文=固定报文
固定报头(2字节)=(MQTT控制报文类型 + 保留位)(1字节)+剩余长度(1字节);例:D0 00

237 MQTT编程实战

(1)MQTT报文总结:
名称 报文流动方向 描述 公式
CONNECT 客户端到服务器 客户端请求连接到服务器 10+剩余长度+00 04 4D 51 54 54 04 C2+保持连接时间+L+设备 ID+L+产品 ID+L+token
CONNACK 服务器到客户端 连接确认 20 02+返回码
SUBSCRIBE 客户端到服务器 客户端请求订阅 82+剩余长度+标识符+L+主题过滤器+QoS
SUBACK 服务器到客户端 订阅确认 90 03+标识符+返回码
PUBLISH 双向 发布消息 30 +剩余长度+L+主题+数据(JSON)
UNSUBSCRIBE 客户端到服务器 请求取消订阅 A2+剩余长度+标识符+主题
UNSUBACK 服务器到客户端 取消订阅确认 B0 02+标识符
PINGREQ 客户端到服务器 心跳请求 C0 00
PINGRESP 服务器到客户端 心跳响应 D0 00
(2)编写连接onenet服务器发送报文相关函数:mqtt登录初始化函数mqtt_login_init(),mqtt初始化函数mqtt_init(),mqtt连接函数mqtt_connect(),MQTT订阅/取消订阅数据打包函数mqtt_subscribe_topic(),
MQTT发布数据打包函数mqtt_publish_data(),mqtt接收函数mqtt_receive_handle(),mqtt发送响应函数mqtt_send_response(),mqtt发送心跳函数mqtt_send_heart(),
mqtt断开连接函数mqtt_disconnect(),mqtt发送数据函数mqtt_send_data();-(60. 温湿度上传OneNET平台-onenet.c,onenet.h)-待分析待测试

238 温湿度上传OneNET项目概述

(1)项目需求:使用 ESP8266 连接 OneNET 云平台,并通过 MQTT 协议上传 DHT11 获取的温湿度值

239 DHT11介绍

(1)DHT11内置一个电阻式感湿元件和一个NTC测温元件,并与一个单片机相连接(DHT11内部)。采用单总线协议,也就是使用一根DATA线进行数据的收发。
DHT11的DATA线一次通讯时间4ms左右,数据分整数部分、小数部分和校验位,具体为:8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。
(2)DHT11工作时序:主机发送开始信号、DHT11 响应输出、主机接收 40bit 数据(湿度数据+温度数据+校验值),结束信号(可选)
(3)起始信号:主机拉低总线至少 18ms,然后再拉高总线,延时 20~40us
响应信号:dht11拉低总线 80us ,之后拉高总线 80us
位数据0表示方式:以50us低电平开始,高电平持续26~28us表示 0
位数据1表示方式:以50us低电平开始,高电平持续70us表示 1
结束信号:DHT11拉低总线50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态

240-241 DHT11实验

(1)编写dht11输入初始化函数dht11_gpio_input(),dht11输出初始化函数dht11dht11_gpio_output(),dht11起始函数dht11_start(),dht11读1个字节函数dht11_read_byte(),dht11读数据函数dht11_read()。-(59. DHT11实验-main.c,dht11.c,dht11.h)-待测试

/*
-------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "dht11.h"
#include "string.h"

int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    printf("hello world!\r\n");
    uint8_t dht11_result[4];
    while(1)
    { 
        memset(dht11_result,0,4);
        dht11_read(dht11_result);
    }
}




/*
-------------------------------------------------------------------------
dht11.c:
-------------------------------------------------------------------------
*/
#include "dht11.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"

char dht11_data[5] = {0};
//编写dht11输入初始化函数dht11_gpio_input()
void dht11_gpio_input(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    DHT11_CLK_ENABLE(); 
    gpio_initstruct.Pin = DHT11_PIN; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(DHT11_PORT,&gpio_initstruct);   
}    
//dht11输出初始化函数dht11dht11_gpio_output()
void dht11_gpio_output(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    DHT11_CLK_ENABLE(); 
    gpio_initstruct.Pin = DHT11_PIN; 
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(DHT11_PORT,&gpio_initstruct);      
}    

//dht11起始函数dht11_start()
void dht11_start(void)
{
    dht11_gpio_output();
    DHT11_DQ_OUT(1);
    DHT11_DQ_OUT(0);
    delay_ms(20);
    DHT11_DQ_OUT(1);
    dht11_gpio_input();
    while(DHT11_DQ_IN);
    while(!DHT11_DQ_IN);
    while(DHT11_DQ_IN);
}    

//dht11读1个字节函数dht11_read_byte()
uint8_t dht11_read_byte(void)
{
    uint8_t temp;
    uint8_t i;
    uint8_t read_data = 0;
    for(i = 0;i < 8;i++)
    {
        while(!DHT11_DQ_IN);
        delay_ms(50);
        if(DHT11_DQ_IN == 1)
        {
            temp = 1;
            while(DHT11_DQ_IN);
        }
        else
            temp = 0;
        read_data = read_data << 1;
        read_data |= temp;   
    }
    return read_data;
}    
//dht11读数据函数dht11_read()
void dht11_read(uint8_t *result)
{
    uint8_t i = 0;
    dht11_start();
    dht11_gpio_input();
    for(i = 0;i < 5;i++)
        dht11_data[i] = dht11_read_byte();
    if(dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3] == dht11_data[4])
    {
        memcpy(result,dht11_data,4);
        printf("湿度:%d.%dRH,",dht11_data[0],dht11_data[1]);
        printf("温度:%d.%d℃\r\n,",dht11_data[2],dht11_data[3]);
    
    }
    delay_ms(2000);
}    


/*
-------------------------------------------------------------------------
dht11.h:
-------------------------------------------------------------------------
*/

#ifndef __DHT11_H__
#define __DHT11_H__
#include "sys.h"
#define DHT11_PORT GPIOA
#define DHT11_PIN GPIO_PIN_5
#define DHT11_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()

#define DHT11_DQ_OUT(x) do{ x ? \
                            HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_SET) : \
                            HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_RESET); \
                        }while(0)
//#define DHT11_DQ_OUT(x)     do{ x ? \
//                                HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET) : \
//                                HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);\
//                            }while(0)
#define DHT11_DQ_IN HAL_GPIO_ReadPin(DHT11_PORT,DHT11_PIN)
void dht11_read(uint8_t *result);                        
#endif

242 温湿度上传OneNET项目完结

(1)添加dht11模块代码,esp8266模块代码,onenet模块代码;esp8266中发送数据函数改写esp8266_send_data(),新增拷贝接收数据函数esp8266_copy_rxdata(),宏定义中TCP_SERVER_IP,TCP_SERVER_PORT修改;
onenet中宏定义中PRODUCT_KEY,DEVICE_NAME,DEVICE_SECRET修改,相关主题修改;主函数中编写dht11读温湿度数据,onenet上发布温湿度主题;-(60. 温湿度上传OneNET平台-main.c,dht11.c,esp8266.c,onenet.c,dht11.h,esp8266.h,onenet.h)-待测试

/*
-------------------------------------------------------------------------
main.c:
-------------------------------------------------------------------------
*/
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "esp8266.h"
#include "dht11.h"
#include "onenet.h"
#include "string.h"
int main(void)
{
    HAL_Init();  /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);   /* 设置时钟, 72Mhz */
    led_init(); /* 初始化LED灯 */
    uart1_init(115200);
    esp8266_init(115200);
    printf("hello world!\r\n");
    printf("MQTT初始化...\r\n");
    mqtt_init();
    printf("MQTT连接...\r\n");
    mqtt_connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord);
    uint8_t data_send[512] ={0};
    uint8_t dht11_data[4] = {0};
    while(1)
    { 
        memset(dht11_data,0,4);
        dht11_read(dht11_data);
        sprintf((char *)data_send, "{\"id\":\"1386772172\",\"version\":\"1.0\",\"params\":{\"CurrentTemperature\":{\"value\":%d.%d},\"CurrentHumidity\":{\"value\":%d.%d}}}",
            dht11_data[2], dht11_data[3], dht11_data[0], dht11_data[1]);
        mqtt_publish_data(POST_TOPIC,(char *)data_send,0);
        delay_ms(3000);
        printf("\r\n~~~~~~~~~~~~~~~~~发送心跳包~~~~~~~~~~~~~~~~~\r\n");
        mqtt_send_heart();
        printf("\r\n~~~~~~~~~~~~~~~~~发送心跳包结束~~~~~~~~~~~~~~~~~\r\n");       
    }
}


/*
-------------------------------------------------------------------------
dht11.c:
-------------------------------------------------------------------------
*/
#include "dht11.h"
#include "delay.h"
#include "string.h"
#include "stdio.h"

char dht11_data[5] = {0};
//编写dht11输入初始化函数dht11_gpio_input()
void dht11_gpio_input(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    DHT11_CLK_ENABLE(); 
    gpio_initstruct.Pin = DHT11_PIN; 
    gpio_initstruct.Mode = GPIO_MODE_INPUT; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(DHT11_PORT,&gpio_initstruct);   
}    
//dht11输出初始化函数dht11dht11_gpio_output()
void dht11_gpio_output(void)
{
    GPIO_InitTypeDef gpio_initstruct;
    DHT11_CLK_ENABLE(); 
    gpio_initstruct.Pin = DHT11_PIN; 
    gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP; 
    gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(DHT11_PORT,&gpio_initstruct);      
}    

//dht11起始函数dht11_start()
void dht11_start(void)
{
    dht11_gpio_output();
    DHT11_DQ_OUT(1);
    DHT11_DQ_OUT(0);
    delay_ms(20);
    DHT11_DQ_OUT(1);
    dht11_gpio_input();
    while(DHT11_DQ_IN);
    while(!DHT11_DQ_IN);
    while(DHT11_DQ_IN);
}    

//dht11读1个字节函数dht11_read_byte()
uint8_t dht11_read_byte(void)
{
    uint8_t temp;
    uint8_t i;
    uint8_t read_data = 0;
    for(i = 0;i < 8;i++)
    {
        while(!DHT11_DQ_IN);
        delay_ms(50);
        if(DHT11_DQ_IN == 1)
        {
            temp = 1;
            while(DHT11_DQ_IN);
        }
        else
            temp = 0;
        read_data = read_data << 1;
        read_data |= temp;   
    }
    return read_data;
}    
//dht11读数据函数dht11_read()
void dht11_read(uint8_t *result)
{
    uint8_t i = 0;
    dht11_start();
    dht11_gpio_input();
    for(i = 0;i < 5;i++)
        dht11_data[i] = dht11_read_byte();
    if(dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3] == dht11_data[4])
    {
        memcpy(result,dht11_data,4);
        printf("湿度:%d.%dRH,",dht11_data[0],dht11_data[1]);
        printf("温度:%d.%d℃\r\n,",dht11_data[2],dht11_data[3]);
    
    }
    delay_ms(2000);
}    








/*
-------------------------------------------------------------------------
esp8266.c:
-------------------------------------------------------------------------
*/
#include "esp8266.h"
#include "stdio.h"
#include "string.h"
#include "delay.h"
#include "stdarg.h"

uint8_t esp8266_rx_buf[ESP8266_RX_BUF_SIZE];
uint8_t esp8266_tx_buf[ESP8266_TX_BUF_SIZE];
uint16_t esp8266_cnt = 0, esp8266_cntPre = 0;

UART_HandleTypeDef esp8266_handle = {0};
void esp8266_uart_init(uint32_t baudrate)
{
    esp8266_handle.Instance = USART1;
    esp8266_handle.Init.BaudRate = baudrate;
    esp8266_handle.Init.WordLength = UART_WORDLENGTH_8B;
    esp8266_handle.Init.StopBits = UART_STOPBITS_1;
    esp8266_handle.Init.Parity = UART_PARITY_NONE;
    esp8266_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    esp8266_handle.Init.Mode = UART_MODE_TX_RX;
    HAL_UART_Init(&esp8266_handle);
}



void USART2_IRQHandler(void)
{
    uint8_t receive_data = 0;
    if(__HAL_UART_GET_FLAG(&esp8266_handle, UART_FLAG_RXNE) != RESET)
    {
        if(esp8266_cnt >= sizeof(esp8266_rx_buf))
            esp8266_cnt = 0;
        HAL_UART_Receive(&esp8266_handle, &receive_data, 1, 1000);
        esp8266_rx_buf[esp8266_cnt++] = receive_data;
        //esp8266_cnt++;
        //HAL_UART_Transmit(&esp8266_handle, &receive_data, 1, 1000);
    }
}



uint8_t esp8266_wait_receive(void)
{
    if(esp8266_cnt == 0)
        return ESP8266_ERROR;
    
    if(esp8266_cnt == esp8266_cntPre)
    {
        esp8266_cnt = 0;
        return ESP8266_EOK;
    }
    
    esp8266_cntPre = esp8266_cnt;
    return ESP8266_ERROR;
}

void esp8266_rx_clear(void)
{
    memset(esp8266_rx_buf, 0, sizeof(esp8266_rx_buf));
    esp8266_cnt = 0;
}

void esp8266_receive_data(void)
{
    if(esp8266_wait_receive() == ESP8266_EOK)
    {
        printf("esp8266 recv: %s\r\n", esp8266_rx_buf);
        esp8266_rx_clear();
    }
}

//void esp8266_send_data(char *fmt, ...)
//{
//    va_list ap;
//    uint16_t len;
//    va_start(ap,fmt);
//    vsprintf((char *)esp8266_tx_buf,fmt,ap);
//    va_end(ap);
//    len = strlen((const char *)esp8266_tx_buf);
//    HAL_UART_Transmit(&esp8266_handle,esp8266_tx_buf,len,100);
//}  
//esp8266中发送数据函数改写esp8266_send_data()
void esp8266_send_data(char *data,uint16_t len)
{
    esp8266_rx_clear();
    HAL_UART_Transmit(&esp8266_handle,(unsigned char *)data,len,100);
}    
//新增拷贝接收数据函数esp8266_copy_rxdata()
uint16_t esp8266_copy_rxdata(char *data)
{
    memcpy(data,esp8266_rx_buf,esp8266_cntPre);
    return esp8266_cntPre;
}    

uint8_t esp8266_send_command(char *cmd,char *res)
{
    uint8_t time_out = 250;
    esp8266_rx_clear();
    HAL_UART_Transmit(&esp8266_handle,(uint8_t *)cmd,strlen(cmd),100);
    while(time_out--)
    {
        if(esp8266_wait_receive() == ESP8266_EOK)
        {
            if(strstr((const char*)esp8266_rx_buf,res) != NULL)
            {
                return ESP8266_EOK;
            }
        }
        delay_ms(10);
    }
    return ESP8266_ERROR;
}
//esp8266的at指令测试
uint8_t esp8266_at_test(void)
{
    return (esp8266_send_command("AT\r\n","OK"));
}    

uint8_t esp8266_set_mode(uint8_t mode)
{
    switch(mode)
    {
        case ESP8266_STA_MODE:
             return esp8266_send_command("AT+CWMODE=1\r\n","OK");
        case ESP8266_AP_MODE:
             return esp8266_send_command("AT+CWMODE=2\r\n","OK");
        case ESP8266_STA_AP_MODE:
             return esp8266_send_command("AT+CWMODE=3\r\n","OK");        
        default:
             return ESP8266_EINVAL;
    
    }                
}


uint8_t esp8266_join_ap(char *ssid,char *pwd)
{
    char cmd[64];
    sprintf(cmd,"AT+CWJAP=\"%s\",\"%s\r\n\"",ssid,pwd);
    return esp8266_send_command(cmd,"WIFI GOT IP");
}

uint8_t esp8266_connection_mode(uint8_t mode)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPMUX=%d\r\n",mode);
    return esp8266_send_command(cmd,"OK");
}

uint8_t esp8266_connect_tcp_server(char *server_ip,char *server_port)
{
    char cmd[64];
    sprintf(cmd,"AT+CIPSTART=\"TCP\",\"%s\",%s\r\n",server_ip,server_port);
    return esp8266_send_command(cmd,"CONNECT"); 
}
uint8_t esp8266_enter_unvarnished(void)
{
    uint8_t ret;
    ret = esp8266_send_command("AT+CIPMODE=1\r\n","OK");
    ret += esp8266_send_command("AT+CIPSEND\r\n",">");
    if(ret == ESP8266_EOK)
        return ESP8266_EOK;
    else
        return ESP8266_ERROR;
}    
void esp8266_init(uint32_t baudrate)
{
    printf("esp8266初始化开始...\r\n");
    esp8266_uart_init(baudrate);
    //esp8266的其他初始化
    printf("1.测试esp8266是否存在...\r\n");
    while(esp8266_at_test())
        delay_ms(500);
    printf("2.设置工作模式为STA...\r\n");
    while(esp8266_set_mode(ESP8266_STA_MODE))
        delay_ms(500);
    printf("3.设置单路链接模式...\r\n");
    while(esp8266_connection_mode(ESP8266_SINGLE_CONNECTION))
        delay_ms(500);
    printf("4.连接wifi,SSID: %s, PWD: %s\r\n",WIFI_SSID,WIFI_PWD);    
    while(esp8266_join_ap(WIFI_SSID,WIFI_PWD))
        delay_ms(1500); 
    printf("5.连接TCP服务器,server_ip: %s, server_port: %s\r\n",TCP_SERVER_IP,TCP_SERVER_PORT);    
    while(esp8266_connect_tcp_server(TCP_SERVER_IP,TCP_SERVER_PORT))
        delay_ms(500);
    printf("6.进入透传模式...\r\n");
    while(esp8266_enter_unvarnished())
        delay_ms(500);
    printf("ESP8266已连接上TCP服务器并进入透传模式\r\n");   
    printf("ESP8266初始化完成!\r\n");    
    
}  


//void esp8266_test(void)
//{
//    esp8266_send_data("this is from esp8266\r\n");
//    esp8266_receive_data();
//}


/*
-------------------------------------------------------------------------
onenet.c:
-------------------------------------------------------------------------
*/
#include "onenet.h"
#include "esp8266.h"

char MQTT_ClientID[100]; //MQTT_客户端ID
char MQTT_UserName[100]; //MQTT_用户名
char MQTT_PassWord[200]; //MQTT_密码

uint8_t *mqtt_rxbuf;
uint8_t *mqtt_txbuf;
uint16_t mqtt_rxlen;
uint16_t mqtt_txlen;
uint8_t _mqtt_txbuf[512];//发送数据缓存区
uint8_t _mqtt_rxbuf[512];//接收数据缓存区

typedef enum
{
    //名字         值             报文流动方向     描述
    M_RESERVED1    =0    ,    //    禁止    保留
    M_CONNECT        ,    //    客户端到服务端    客户端请求连接服务端
    M_CONNACK        ,    //    服务端到客户端    连接报文确认
    M_PUBLISH        ,    //    两个方向都允许    发布消息
    M_PUBACK        ,    //    两个方向都允许    QoS 1消息发布收到确认
    M_PUBREC        ,    //    两个方向都允许    发布收到(保证交付第一步)
    M_PUBREL        ,    //    两个方向都允许    发布释放(保证交付第二步)
    M_PUBCOMP        ,    //    两个方向都允许    QoS 2消息发布完成(保证交互第三步)
    M_SUBSCRIBE        ,    //    客户端到服务端    客户端订阅请求
    M_SUBACK        ,    //    服务端到客户端    订阅请求报文确认
    M_UNSUBSCRIBE    ,    //    客户端到服务端    客户端取消订阅请求
    M_UNSUBACK        ,    //    服务端到客户端    取消订阅报文确认
    M_PINGREQ        ,    //    客户端到服务端    心跳请求
    M_PINGRESP        ,    //    服务端到客户端    心跳响应
    M_DISCONNECT    ,    //    客户端到服务端    客户端断开连接
    M_RESERVED2        ,    //    禁止    保留
}_typdef_mqtt_message;

//连接成功服务器回应 20 02 00 00
//客户端主动断开连接 e0 00
const uint8_t parket_connetAck[] = {0x20,0x02,0x00,0x00};
const uint8_t parket_disconnet[] = {0xe0,0x00};
const uint8_t parket_heart[] = {0xc0,0x00};
const uint8_t parket_heart_reply[] = {0xc0,0x00};
const uint8_t parket_subAck[] = {0x90,0x03};

/*
函数功能: 初始化阿里云物联网服务器的登录参数
*/


//密码
//加密之前的数据格式:  clientId*deviceName*productKey#
// *替换为DeviceName  #替换为ProductKey  加密密钥是DeviceSecret  加密方式是HmacSHA1  
//PassWord明文=  clientIdiot_devicedeviceNameiot_deviceproductKeya1VMIfYeEEE
//hmacsha1加密网站:http://encode.chahuo.com/
//加密的密钥:DeviceSecret

void mqtt_login_init(char *ProductKey,char *DeviceName,char *DeviceSecret)
{
//    sprintf(MQTT_ClientID,"%s.%s|securemode=2,signmethod=hmacsha256,timestamp=1695871022945|",ProductKey,DeviceName);
//    sprintf(MQTT_UserName,"%s&%s",DeviceName,ProductKey);
//    sprintf(MQTT_PassWord,"%s","a8921500839307ec3fedbbcd8c0cbc19f133f68c831dcad41fe13d92dc90b89d");
    sprintf(MQTT_ClientID,"%s", DeviceName);
    sprintf(MQTT_UserName,"%s", ProductKey);
    sprintf(MQTT_PassWord,"version=2018-10-31&res=products%%2F%s%%2Fdevices%%2F%s&et=2017881776&method=sha1&sign=%s",ProductKey,DeviceName,DEVICE_SECRET);
}

void mqtt_init(void)
{
    mqtt_login_init(PRODUCT_KEY,DEVICE_NAME,DEVICE_SECRET);
    //缓冲区赋值
    mqtt_rxbuf = _mqtt_rxbuf;
    mqtt_rxlen = sizeof(_mqtt_rxbuf);
    mqtt_txbuf = _mqtt_txbuf;
    mqtt_txlen = sizeof(_mqtt_txbuf);
    memset(mqtt_rxbuf,0,mqtt_rxlen);
    memset(mqtt_txbuf,0,mqtt_txlen);
    
    //无条件先主动断开
    mqtt_disconnect();
    delay_ms(100);
    mqtt_disconnect();
    delay_ms(100);
}

/*
函数功能: 登录服务器
函数返回值: 0表示成功 1表示失败
*/
uint8_t mqtt_connect(char *ClientID,char *Username,char *Password)
{
//    uint8_t i;
    uint8_t j;
    int ClientIDLen = strlen(ClientID);
    int UsernameLen = strlen(Username);
    int PasswordLen = strlen(Password);
    int DataLen;
    mqtt_txlen=0;
    //可变报头+Payload  每个字段包含两个字节的长度标识
    DataLen = 10 + (ClientIDLen+2) + (UsernameLen+2) + (PasswordLen+2);
    
    //固定报头
    //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x10;        //MQTT Message Type CONNECT
    //剩余长度(不包括固定头部)
    do
    {
        uint8_t encodedByte = DataLen % 128;
        DataLen = DataLen / 128;
        // if there are more data to encode, set the top bit of this byte
        if ( DataLen > 0 )
            encodedByte = encodedByte | 128;
        mqtt_txbuf[mqtt_txlen++] = encodedByte;
    }while ( DataLen > 0 );
        
    //可变报头
    //协议名
    mqtt_txbuf[mqtt_txlen++] = 0;            // Protocol Name Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 4;           // Protocol Name Length LSB    
    mqtt_txbuf[mqtt_txlen++] = 'M';            // ASCII Code for M    
    mqtt_txbuf[mqtt_txlen++] = 'Q';            // ASCII Code for Q    
    mqtt_txbuf[mqtt_txlen++] = 'T';            // ASCII Code for T    
    mqtt_txbuf[mqtt_txlen++] = 'T';            // ASCII Code for T    
    //协议级别
    mqtt_txbuf[mqtt_txlen++] = 4;                // MQTT Protocol version = 4    
    //连接标志
    mqtt_txbuf[mqtt_txlen++] = 0xc2;            // conn flags 
    mqtt_txbuf[mqtt_txlen++] = 0;                // Keep-alive Time Length MSB    
    mqtt_txbuf[mqtt_txlen++] = 100;            // Keep-alive Time Length LSB  100S心跳包  
    
    mqtt_txbuf[mqtt_txlen++] = BYTE1(ClientIDLen);// Client ID length MSB    
    mqtt_txbuf[mqtt_txlen++] = BYTE0(ClientIDLen);// Client ID length LSB      
    memcpy(&mqtt_txbuf[mqtt_txlen],ClientID,ClientIDLen);
    mqtt_txlen += ClientIDLen;
    
    if(UsernameLen > 0)
    {   
        mqtt_txbuf[mqtt_txlen++] = BYTE1(UsernameLen);        //username length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(UsernameLen);        //username length LSB    
        memcpy(&mqtt_txbuf[mqtt_txlen],Username,UsernameLen);
        mqtt_txlen += UsernameLen;
    }
    
    if(PasswordLen > 0)
    {    
        mqtt_txbuf[mqtt_txlen++] = BYTE1(PasswordLen);        //password length MSB    
        mqtt_txbuf[mqtt_txlen++] = BYTE0(PasswordLen);        //password length LSB  
        memcpy(&mqtt_txbuf[mqtt_txlen],Password,PasswordLen);
        mqtt_txlen += PasswordLen; 
    }    
    
//    for(i=0;i<10;i++)
//    {
        memset(mqtt_rxbuf,0,mqtt_rxlen);
        mqtt_send_data(mqtt_txbuf,mqtt_txlen);
//        for(j=0;j<10;j++)
//            printf("%c",mqtt_txbuf[j]);
        for(j=0;j<10;j++)
        {
            delay_ms(50);
            if (esp8266_wait_receive() == ESP8266_EOK)
                esp8266_copy_rxdata((char *)mqtt_rxbuf);

            //CONNECT
            if(mqtt_rxbuf[0]==parket_connetAck[0] && mqtt_rxbuf[1]==parket_connetAck[1] && mqtt_rxbuf[2]==parket_connetAck[2]) //连接成功
            {
                return 0;//连接成功
            }
        }
//    }
    return 1;
}

/*
函数功能: MQTT订阅/取消订阅数据打包函数
函数参数:
    topic       主题   
    qos         消息等级 0:最多分发一次  1: 至少分发一次  2: 仅分发一次
    whether     订阅/取消订阅请求包 (1表示订阅,0表示取消订阅)
返回值: 0表示成功 1表示失败
*/
uint8_t mqtt_subscribe_topic(char *topic,uint8_t qos,uint8_t whether)
{    
//    uint8_t i;
    uint8_t j;
    mqtt_txlen=0;
    int topiclen = strlen(topic);
    
    int DataLen = 2 + (topiclen+2) + (whether?1:0);//可变报头的长度(2字节)加上有效载荷的长度
    //固定报头
    //控制报文类型
    if(whether)mqtt_txbuf[mqtt_txlen++] = 0x82; //消息类型和标志订阅
    else    mqtt_txbuf[mqtt_txlen++] = 0xA2;    //取消订阅

    //剩余长度
    do
    {
        uint8_t encodedByte = DataLen % 128;
        DataLen = DataLen / 128;
        // if there are more data to encode, set the top bit of this byte
        if ( DataLen > 0 )
            encodedByte = encodedByte | 128;
        mqtt_txbuf[mqtt_txlen++] = encodedByte;
    }while ( DataLen > 0 );    
    
    //可变报头
    mqtt_txbuf[mqtt_txlen++] = 0;            //消息标识符 MSB
    mqtt_txbuf[mqtt_txlen++] = 0x01;        //消息标识符 LSB
    //有效载荷
    mqtt_txbuf[mqtt_txlen++] = BYTE1(topiclen);//主题长度 MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topiclen);//主题长度 LSB   
    memcpy(&mqtt_txbuf[mqtt_txlen],topic,topiclen);
    mqtt_txlen += topiclen;
    
    if(whether)
    {
       mqtt_txbuf[mqtt_txlen++] = qos;//QoS级别
    }
    
//    for(i=0;i<10;i++)
//    {
        memset(mqtt_rxbuf,0,mqtt_rxlen);
        mqtt_send_data(mqtt_txbuf,mqtt_txlen);

        for(j=0;j<10;j++)
        {
            delay_ms(50);
            if (esp8266_wait_receive() == ESP8266_EOK)
                esp8266_copy_rxdata((char *)mqtt_rxbuf);

            if(mqtt_rxbuf[0]==parket_subAck[0] && mqtt_rxbuf[1]==parket_subAck[1]) //订阅成功               
            {
                return 0;//订阅成功
            }
        }
//    }
    return 1; //失败
}

//MQTT发布数据打包函数
//topic   主题 
//message 消息
//qos     消息等级 
uint8_t mqtt_publish_data(char *topic, char *message, uint8_t qos)
{  
    int topicLength = strlen(topic);    
    int messageLength = strlen(message);     
    static uint16_t id=0;
    int DataLen;
    mqtt_txlen=0;
    //有效载荷的长度这样计算:用固定报头中的剩余长度字段的值减去可变报头的长度
    //QOS为0时没有标识符
    //数据长度             主题名   报文标识符   有效载荷
    if(qos)    DataLen = (2+topicLength) + 2 + messageLength;       
    else    DataLen = (2+topicLength) + messageLength;   

    //固定报头
    //控制报文类型
    mqtt_txbuf[mqtt_txlen++] = 0x30;    // MQTT Message Type PUBLISH  

    //剩余长度
    do
    {
        uint8_t encodedByte = DataLen % 128;
        DataLen = DataLen / 128;
        // if there are more data to encode, set the top bit of this byte
        if ( DataLen > 0 )
            encodedByte = encodedByte | 128;
        mqtt_txbuf[mqtt_txlen++] = encodedByte;
    }while ( DataLen > 0 );    
    
    mqtt_txbuf[mqtt_txlen++] = BYTE1(topicLength);//主题长度MSB
    mqtt_txbuf[mqtt_txlen++] = BYTE0(topicLength);//主题长度LSB 
    memcpy(&mqtt_txbuf[mqtt_txlen],topic,topicLength);//拷贝主题
    mqtt_txlen += topicLength;
        
    //报文标识符
    if(qos)
    {
        mqtt_txbuf[mqtt_txlen++] = BYTE1(id);
        mqtt_txbuf[mqtt_txlen++] = BYTE0(id);
        id++;
    }
    memcpy(&mqtt_txbuf[mqtt_txlen],message,messageLength);
    mqtt_txlen += messageLength;

//    int i = 0;
//    for(i=0;i<mqtt_txlen;i++)
//        printf("%02X ", mqtt_txbuf[i]);
//    printf("\r\n");
    mqtt_send_data(mqtt_txbuf,mqtt_txlen);
    return mqtt_txlen;
}

uint8_t mqtt_receive_handle(uint8_t *data_received, Mqtt_RxData_Type *rx_data)
{
    uint8_t *p;
    uint8_t encodeByte = 0;
    uint32_t multiplier = 1, Remaining_len = 0;
    uint8_t QS_level = 0;
    
    p = data_received;
    memset(rx_data, 0, sizeof(Mqtt_RxData_Type));
    
    //解析接收数据
    if((*p != 0x30)&&(*p != 0x32)&&(*p != 0x34))   //不是发布报文头
        return 1;
    
    if(*p != 0x30) QS_level = 1;    //标记qs等级不为0
    
    p++;
    //提取剩余数据长度
    do{
        encodeByte = *p++;
        Remaining_len += (encodeByte & 0x7F) * multiplier;
        multiplier *= 128;
        
        if(multiplier > 128*128*128) //超出剩余长度最大4个字节的要求,错误
            return 2;
    }while((encodeByte & 0x80) != 0);
    
    //提取主题数据长度
    rx_data->topic_len = *p++;
    rx_data->topic_len = rx_data->topic_len * 256 + *p++;
    //提取主题
    memcpy(rx_data->topic,p,rx_data->topic_len);
    p += rx_data->topic_len;
    
    if(QS_level != 0)  //跳过报文标识符
        p += 2;
    
    //提取payload
    rx_data->payload_len = Remaining_len - rx_data->topic_len - 2;
    memcpy(rx_data->payload, p, rx_data->payload_len);
    
//    printf("topic: %s\r\n", rx_data->topic);
//    printf("topic_len: %d\r\n", rx_data->topic_len);
//    printf("payload: %s\r\n", rx_data->payload);
//    printf("payload_len: %d\r\n", rx_data->payload_len);

    return 0;
}

void mqtt_send_response(uint8_t *id)
{
    char buf[128] = {0};
    sprintf(buf,"{\"id\":\"%s\",\"code\":200,\"msg\":\"success\"}",id);
    
    mqtt_publish_data(RELY_PUBLISH_TOPIC,(char *)buf,0);
    
    printf("\r\n发布数据:\r\n");
    printf((const char *)buf);    //发布的数据打印出来
    printf("\r\n");
}

void mqtt_send_heart(void)
{
    mqtt_send_data((uint8_t *)parket_heart,sizeof(parket_heart));
}

void mqtt_disconnect(void)
{
    mqtt_send_data((uint8_t *)parket_disconnet,sizeof(parket_disconnet));
}

void mqtt_send_data(uint8_t *buf,uint16_t len)
{
    esp8266_send_data((char *)buf, len);
}


/*
-------------------------------------------------------------------------
dht11.h:
-------------------------------------------------------------------------
*/
#ifndef __DHT11_H__
#define __DHT11_H__
#include "sys.h"
#define DHT11_PORT GPIOA
#define DHT11_PIN GPIO_PIN_5
#define DHT11_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE()

#define DHT11_DQ_OUT(x) do{ x ? \
                            HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_SET) : \
                            HAL_GPIO_WritePin(DHT11_PORT,DHT11_PIN,GPIO_PIN_RESET); \
                        }while(0)
//#define DHT11_DQ_OUT(x)     do{ x ? \
//                                HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET) : \
//                                HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);\
//                            }while(0)
#define DHT11_DQ_IN HAL_GPIO_ReadPin(DHT11_PORT,DHT11_PIN)
void dht11_read(uint8_t *result);                        
#endif


/*
-------------------------------------------------------------------------
esp8266.h:
-------------------------------------------------------------------------
*/
#ifndef __ESP8266_H__
#define __ESP8266_H__

#include "sys.h"

#define ESP8266_RX_BUF_SIZE  128
#define ESP8266_TX_BUF_SIZE  64

#define ESP8266_EOK        0
#define ESP8266_ERROR      1
#define ESP8266_ETIMEOUT   2
#define ESP8266_EINVAL     3

#define ESP8266_STA_MODE 1
#define ESP8266_AP_MODE 2
#define ESP8266_STA_AP_MODE 3

#define WIFI_SSID "wifi账号"
#define WIFI_PWD  "wifi密码"

#define ESP8266_SINGLE_CONNECTION 0
#define ESP8266_MULTI_CONNECTION 1

#define TCP_SERVER_IP "主机ip地址"
#define TCP_SERVER_PORT "主机端口号"

void esp8266_init(uint32_t baudrate);
void esp8266_receive_data(void);
//void esp8266_test(void);
void esp8266_send_data(char *data,uint16_t len);
uint16_t esp8266_copy_rxdata(char *data);
uint8_t esp8266_wait_receive(void);

#endif

/*
-------------------------------------------------------------------------
onenet.h:
-------------------------------------------------------------------------
*/
#ifndef _ONENET_H_
#define _ONENET_H_

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "delay.h"

#define BYTE0(dwTemp)       (*( char *)(&dwTemp))
#define BYTE1(dwTemp)       (*((char *)(&dwTemp) + 1))
#define BYTE2(dwTemp)       (*((char *)(&dwTemp) + 2))
#define BYTE3(dwTemp)       (*((char *)(&dwTemp) + 3))
    
extern char MQTT_ClientID[100]; //MQTT_客户端ID
extern char MQTT_UserName[100]; //MQTT_用户名
extern char MQTT_PassWord[200]; //MQTT_密码

typedef struct
{
    uint8_t topic[512];
    uint16_t topic_len;
    uint8_t payload[512];
    uint16_t payload_len;
} Mqtt_RxData_Type;


//onenet中宏定义中PRODUCT_KEY,DEVICE_NAME,DEVICE_SECRET修改,相关主题修改;

//云服务器的设备证书
#define PRODUCT_KEY "pC0uTV161W"
#define DEVICE_NAME "dht11_01"
#define DEVICE_SECRET "75AKO7FD5KBEuSJ6BTDLPFC227w%3D"

//订阅与发布的主题
#define RELY_PUBLISH_TOPIC  "$sys/pC0uTV161W/dht11_01/thing/property/set_reply"  //属性设置应答订阅主题,onenet studio定义好的
#define SET_TOPIC  "$sys/pC0uTV161W/dht11_01/thing/property/set"
#define POST_TOPIC "$sys/pC0uTV161W/dht11_01/thing/property/post"
//事件上报主题
#define EVENT_PUBLISH_TOPIC   "$sys/pC0uTV161W/dht11_01/thing/event/post"  //发布主题,onenet studio定义好的

//阿里云用户名初始化
void mqtt_login_init(char *ProductKey,char *DeviceName,char *DeviceSecret);
//MQTT协议相关函数声明
uint8_t mqtt_publish_data(char *topic, char *message, uint8_t qos);
uint8_t mqtt_subscribe_topic(char *topic,uint8_t qos,uint8_t whether);
void mqtt_init(void);
uint8_t mqtt_connect(char *ClientID,char *Username,char *Password);
void mqtt_send_heart(void);
void mqtt_disconnect(void);
void mqtt_send_data(uint8_t *buf,uint16_t len);
void mqtt_send_response(uint8_t *id);
uint8_t mqtt_receive_handle(uint8_t *data_received, Mqtt_RxData_Type *rx_data);
#endif

243 天气预报项目概述

(1)项目需求:使用 ESP8266 通过 HTTP 获取天气数据(心知天气),并显示在 OLED 屏幕上。
按键 1 :循环切换今天/明天/后天天气数据;
按键 2 :更新天气。

244 心知天气平台详解

(1)心知天气网址:https://www.seniverse.com/; 注册登录后获取密钥SkzfX1jdvaAJrPNak,查手册获取心知天气平台服务器 api.seniverse.com及端口号80,手册中获取近5天天气的api,
根据api获取自己想要了解的城市近期天气状况(例:https://api.seniverse.com/v3/weather/daily.json?key=SkzfX1jdvaAJrPNak&location=pingxiang&language=zh-Hans&unit=c&start=0&days=5 );

245 cJSON介绍

(1)github中DaveGamble中下载cJSON库文件,cJSON库文件可打包及拆解json格式,利用JSON在线工具可校验/格式化json代码;

246 项目框架搭建及OLED模块修改

(1)添加cJSON模块代码,esp8266模块代码,key模块代码,oled模块代码;oled中引脚修改,font中新增所需文字字模,修改oled汉字显示函数oled_show_chinese(),新增oled初始化显示函数oled_show_init();-(61. 天气预报项目-oled.c,oled.h,font.h)–待测试

247 esp8266模块代码完善

(1)esp8266中新增拷贝接收的数据函数esp8266_copy_rxdata(),获取天气函数esp8266_get_weather(),修改esp8266.h中TCP_SERVER_IP,TCP_SERVER_PORT宏定义,以及ESP8266_RX_BUF_SIZE大小。-(61. 天气预报项目-esp8266.c,esp8266.h)–待测试

248-249 weather模块代码编写

(1)修改startup_stm32f101xb.s文件中堆Heap_Size的值,新建weather.c,新增获取3天天气函数get_3days_weather();-(61. 天气预报项目-weather.c,weather.h)–待测试
(2)对获取3天天气函数get_3days_weather()进行解析;-(61. 天气预报项目-weather.c,weather.h)–待测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值