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)–待测试