基于STC8G芯片的时钟显示系统
这里写目录标题
一、电路原理图设计
1.1EDA__立创EDA
1.1.1 主要器件BOM–仅供参考
ID | Name | Footprint | Supplier | Price |
---|---|---|---|---|
1 | STC8G2K64S4 | LQFP-32 | C915671 | ¥8 |
2 | 11.0592MHZ | HC-49US | C358645 | ¥0.7869 |
3 | LED | LED-SMD | C375449 | ¥0.1071 |
4 | KEY | KEY-TH_4P | C2762975 | ¥0.6092 |
5 | AMS1117-3.3 | SOT-223 | C6186 | ¥0.9204 |
6 | 电容C | 0603 | ||
7 | 电阻R | 0603 | ||
8 | MAX7129 | 网络购买 | 数码管 | ¥3.42 |
9 | DHT11 | 网络购买 | 温湿度 | ¥4.00 |
10 | OLED 0.91 | 网络购买 | OLED | ¥7.40 |
11 | HC05 | 网络购买 | 蓝牙 | ¥18 |
12 | BC95 | 网络购买 | NB | ¥89 |
13 | DC电源插头插座 | 网络购买 | 电源 | ¥0.4 |
1.1.2主要电路原理图设计
①电源原理图
U8—DC直流电源插头插座: 用于5V适配器供电;
网络购买封装自己添加
U4–AMS1117-3.3 :用于5V转3.3V;
② 数码管原理图
U10/U3—MAX7129: 用于显示数字;
网络购买封装自己添加
实物参考
两个MAX7129电路设计为串联
③ STC8G原理图
STC8G主芯片网络标号连接
④ 下载口原理图
串口 1引出:用于下载
下载驱动
⑤ 按键原理图
⑥ 无线通信模块原理图
无线通信模块–兼容两种无线通信
NB模块-BC-95
4G模块-WH-LTE-7S1
封装自己按照尺寸画的;
WH-LTE-7S1介绍
WH-LTE-7S1_hareware_V1.0.2文档获取以下信息
①供电----DC5-16V
②串口通信----TTL
③模块复位----RESET
(2)串口调试助手测试
测试工具
查看USR-Cat-1_AT_ V1.0.5文档
按照AT指令的标准进行“问”与“答”
⑥ 辅助模块原理图
电源指示灯 --用于电源指示
程序状态灯 --用于程先生状态显示
晶振电路 --用于时钟系统
复位电路 --用于复位
⑥ 外设模块原理图
串口3 ----用于蓝牙模块透传
DHT11 ----用于温湿度获取
OLED ----用于数据显示
1.2 PCB
1.2.1顶层
1.2.2底层
1.2.3 2D
1.2.4 3D
二、程序设计
2.1 主函数程序
// 主逻辑函数 默认上电日期2023-03-17- 08:00:00
系统自加时间;
系统记忆亮度等级为5;
struct ctm {
char issync;
char isleap;
char tm_year; /* years since 1900 */
char tm_mon; /* months since January, 0 to 11 */
char tm_mday; /* day of the month, 1 to 31 */
char tm_hour; /* hours since midnight, 0 to 23 */
char tm_min; /* minutes after the hour, 0 to 59 */
char tm_sec; /* seconds after the minute, 0 to 60*/
};
struct ctm c_lct;
#define JAN_2014_1970 0x52c35a80 /* 3187296000 2001 - 1900 in seconds */
//初始化时间
void Init_value(void)
{
t_utc=JAN_2014_1970;//计算日期(设备上电请求时间)必须大于等于2003年,否则NTP计算将会溢出(long类型)
c_lct.tm_sec=0;
c_lct.tm_min=0;
c_lct.tm_hour=08;
c_lct.tm_mday=17;
c_lct.tm_mon=03;
c_lct.tm_year=23; /* years since 2000 */
}
// 主程序 ---------------------
void main()
{
Init_value();
Init_MSP();
ReadCfg();
EA_On(); //使能总中断
Init_Cat();
SendSyncEn=P21;
SetWriteFlag(0);
while (1)
{
Wdt_fresh(); //清看门狗,否则系统复位
Task_WDT(); //清外部看门狗813,否则系统复位
Task_Max7219(TASKS_LED);
#if defined(CAT)
Task_Cat(TASKS_CAT);
#elif defined(NB)
Task_Cat(TASKS_NB);
#endif
}
}
2.2 系统初始化程序
// 系统初始化函数
初始化时钟
初始化IO
初始化串口
初始化看门狗
初始化定时器0
初始化定时器2
void IO_Init(void)
{
P0M1 = 0;
P0M0 = 0; //设置为准双向口,M1M0:00=准双向口,01=推挽,10=高阻,11=开漏
P1M1 = 0;
P1M0 = 0; //设置为准双向口,M1M0:00=准双向口,01=推挽,10=高阻,11=开漏
P2M1 = 0;
P2M0 = 0; //设置为准双向口,M1M0:00=准双向口,01=推挽,10=高阻,11=开漏
P3M1 = 0;
P3M0 = 0; //设置为准双向口,M1M0:00=准双向口,01=推挽,10=高阻,11=开漏
P1M0 |= 0x10; //设置P14为推挽输出
P2M0 |= 0x0E; //设置P21,P22,P23为推挽输出
}
void EA_On(void)
{
EA = 1; //使能总中断
}
void Init_MSP(void)
{
SystemClock_Config(); //初始化时钟
IO_Init();
Wdt_Config(); //初始化看门狗
TM0_Init(3); //初始化定时器0,频率200HZ,优先级3。
TM2_Baud_Init(); //初始化定时器2做串口1,2,3,4通用波特率发生器,优先级固定为最低优先级0
#ifdef USE_UART1
UART1_Init(0,UART1_BPR); //初始化串口1
#endif
#ifdef USE_UART2
UART2_Init(); //初始化串口2
#endif
#ifdef USE_UART3
UART3_Init(1, UART3_BPR); //初始化串口3
#endif
#ifdef USE_UART4
UART4_Init(1, UART4_BPR); //初始化串口4,
#endif
}
2.3 串口驱动程序
// 串口1/2/3/4驱动函数
#ifdef USE_UART1
void UART1_Init(unsigned char mode, unsigned int baud) //串口1、2可设优先级,串口3、4固定为最低优先级0,mode=0,使用默认定时器波特率
{
SCON = 0x50; //串口1控制寄存器SCON(可位访问)选用串口方式1(可变8位,0x40) ,允许串口接收数据(0x10)
PCON &= (~(SMOD | SMOD0)); //电源管理寄存器PCON(不可位访问),串口1波特率不加倍,无帧错检测功能
AUXR &= (~(UART_M0x6 | S1ST2)); //辅助寄存器1 AUXR(不可位访问),串口1方式0波特率不加6倍,定时器1做串口1波特率发生器
if(mode > 0) //定时器1做串口1波特率发生器 //串口1可用定时器2和定时器1做波特率发生器
{
TMOD &= 0x0f; //定时器0/1模式寄存器TMOD(不可位访问),定时器1,模式0(16位自动重载模式)
AUXR |= T1x12; //辅助寄存器1 AUXR(不可位访问),定时器1以系统不分频
INTCLKO &= (~T1CLKO); //中断与时钟输出控制寄存器INTCLKO(不可位访问),关闭定时器1时钟输出
TH1 = (-SYSCLK / baud / 4) >> 8;
TL1 = (-SYSCLK / baud / 4); //65536-11059200/115200/4=0FFE8H
TR1 = 1; //定时器0/1、外部中断0/1控制寄存器TCON(可位访问),启动定时器1
}
else
{
AUXR |= S1ST2; //辅助寄存器1 AUXR(不可位访问),定时器2做串口1波特率发生器
}
ES = 1; //中断使能寄存器IE(可位访问) 使能串口1中断
}
void send_uart1( unsigned char *_ucaBuf, int _usLen)
{
if(_usLen>0)
{
tx_num1=_usLen;
tx_cnt1=1;
pMsg1= _ucaBuf;
SBUF = *pMsg1++;
}
}
int get_uart1( unsigned char *_ucaBuf)
{
int temp = 0;
if(rx_t1>=UOUT_TIME)
{
if(rx_cnt1>0)
{
memcpy (_ucaBuf, rxBuf1, rx_cnt1);
temp=rx_cnt1;
rx_cnt1=0;//重新开始接收,接收完置位,表明停止接收了
}
}
return temp;
}
#endif
#ifdef USE_UART2
void UART2_Init(void)//串口1、2可设优先级,串口3、4固定为最低优先级0,mode=0,使用默认定时2器波特率
{
//串口2只能用定时器2作为波特率发生器
S2CON = S2REN; //串口2控制寄存器S2CON(不可位访问),选用串口方式0(可变8位) ,允许串口接收数据(0x10) ,
IE2 |= ES2; //中断使能寄存器2 IE2(不可位访问)使能串口2中断
}
void send_uart2( unsigned char *_ucaBuf, int _usLen)
{
if(_usLen>0)
{
tx_num2=_usLen;
tx_cnt2=1;
pMsg2=(unsigned char xdata *)_ucaBuf;
S2BUF = *pMsg2++;
}
}
int get_uart2( unsigned char *_ucaBuf)
{
int temp = 0;
if(rx_t2>=UOUT_TIME)
{
if(rx_cnt2>0)
{
memcpy (_ucaBuf, rxBuf2, rx_cnt2);
temp=rx_cnt2;
rx_cnt2=0;//重新开始接收,接收完置位,表明停止接收了
}
}
return temp;
}
#endif
#ifdef USE_UART3
void UART3_Init(unsigned char mode, unsigned int baud) //串口1、2可设优先级,串口3、4固定为最低优先级0,mode=0,使用默认定时器2波特率
{
if(mode > 0) //定时器3做串口3波特率发生器 //串口3可用定时器2和定时器3做波特率发生器
{
S3CON = S3ST3 | S3REN; //串口3控制寄存器S3CON(不可位访问)串口方式0(可变8位),允许串口接收数据(0x10) ,选用定时器3作为波特率发生器
//TM3PS //定时器3的8位预分频寄存器(TM3PS),默认为0 定时器2时钟=系统时钟SYSCLK/(TM3PS+1)
T3H = (-SYSCLK / baud / 4) >> 8;
T3L = (-SYSCLK / baud / 4); //65536-11059200/115200/4=0FFE8H
T4T3M &= 0xf0;
T4T3M |= (T3R | T3x12); //启动定时器3,定时器以系统不分频
}
else//定时器2做串口3波特率发生器,注意与其它串口参数的影响
{
S3CON = S3REN; //串口3控制寄存器S3CON(不可位访问)串口方式0(可变8位),允许串口接收数据(0x10) ,默认选用定时器2作为波特率发生器
}
IE2 |= ES3; //中断使能寄存器2 IE2(不可位访问)使能串口3中断
}
void send_uart3( unsigned char *_ucaBuf, int _usLen)
{
if(_usLen>0 )
{
tx_num3=_usLen;
tx_cnt3=1;
pMsg3=(unsigned char xdata *)_ucaBuf;
S3BUF = *pMsg3++;
}
#endif
#ifdef USE_UART4
void UART4_Init(unsigned char mode, unsigned int baud) //串口1、2可设优先级,串口3、4固定为最低优先级0,mode=0,使用默认定时器2波特率
{
if(mode > 0) //定时器4做串口4波特率发生器 //串口4可用定时器2和定时器4做波特率发生器
{
S4CON = S4ST4 | S4REN; //串口4控制寄存器S4CON(不可位访问)串口方式0(可变8位),允许串口接收数据(0x10) ,选用定时器4作为波特率发生器
//TM4PS //定时器4的8位预分频寄存器(TM4PS),默认为0 定时器2时钟=系统时钟SYSCLK/(TM4PS+1)
T4H = (-SYSCLK / baud / 4) >> 8;
T4L = (-SYSCLK / baud / 4); //65536-11059200/115200/4=0FFE8H
T4T3M &= 0x0f;
T4T3M |= (T4R | T4x12); //启动定时器4,定时器以系统不分频
}
else//定时器2做串口4波特率发生器,注意与其它串口参数的影响
{
S4CON = S4REN; //串口4控制寄存器S4CON(不可位访问)串口方式0(可变8位),允许串口接收数据(0x10) ,默认选用定时器2作为波特率发生器
}
IE2 |= ES4; //中断使能寄存器2 IE2(不可位访问)使能串口4中断
}
void send_uart4( unsigned char *_ucaBuf, int _usLen)
{
if(_usLen>0)
{
tx_num4=_usLen;
tx_cnt4=1;
pMsg4=(unsigned char xdata *)_ucaBuf;
S4BUF = *pMsg4++;
}
}
int get_uart4( unsigned char *_ucaBuf)
{
int temp = 0;
if(rx_t4>=UOUT_TIME)
{
if(rx_cnt4>0)
{
memcpy (_ucaBuf, rxBuf4, rx_cnt4);
temp=rx_cnt4;
rx_cnt4=0;//重新开始接收,接收完置位,表明停止接收了
}
}
return temp;
}
unsigned char get_uart4_tx_idle(void)
{
if(tx_cnt4==tx_num4)return 1;
else return 0;
}
void set_uart4_tx_clr(void)
{
tx_num4=0;
tx_cnt4=0;
}
#endif
2.4 看门狗驱动程序
// 看门狗驱动函数
看门狗喂狗函数
void Wdt_Config(void)
{
WDT_CONTR = 0x27; //使能看门狗,溢出时间约为8s
}
void Wdt_fresh(void)
{
WDT_CONTR |= CLR_WDT; //清看门狗,否则系统复位
}
void delay_ms(int t)
{
static int lms=0;
int mt=t;
while(mt>0)
{
if(lms!=mscnt)//5ms一次
{
lms=mscnt;
mt-=MS_TICK;
}
Wdt_fresh(); //清看门狗,否则系统复位
Task_WDT(); //清外部看门狗813,否则系统复位
}
}
2.5 掉电记忆程序
// 掉电记忆写函数
掉电记忆读函数
void IapIdle()
{
IAP_CONTR = 0; //关闭IAP功能
IAP_CMD = 0; //清除命令寄存器
IAP_TRIG = 0; //清除触发寄存器
IAP_ADDRH = 0x80; //将地址设置到非IAP区域
IAP_ADDRL = 0;
}
unsigned char IapRead(unsigned int addr)
{
unsigned char dat;
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置擦除等待参数12MHZ
IAP_CMD = 1; //设置IAP读命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
dat = IAP_DATA; //读IAP数据
IapIdle(); //关闭IAP功能
return dat;
}
void IapProgram(unsigned int addr, unsigned char dat)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置擦除等待参数12MHZ
IAP_CMD = 2; //设置IAP写命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_DATA = dat; //写IAP数据
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_();
IapIdle(); //关闭IAP功能
}
void IapErase(unsigned int addr)
{
IAP_CONTR = 0x80; //使能IAP
IAP_TPS = 12; //设置擦除等待参数12MHZ
IAP_CMD = 3; //设置IAP擦除命令
IAP_ADDRL = addr; //设置IAP低地址
IAP_ADDRH = addr >> 8; //设置IAP高地址
IAP_TRIG = 0x5a; //写触发命令(0x5a)
IAP_TRIG = 0xa5; //写触发命令(0xa5)
_nop_(); //
IapIdle(); //关闭IAP功能
}
void WirteCfg(void)
{
IapErase(0x00);//擦除从0开始的一个扇区,512个字节
IapProgram(0x01, CfgData[1]);//写入亮度
IapProgram(0x02, CfgData[2]);//写入通讯时长高
IapProgram(0x03, CfgData[3]);//写入通讯时长低
CfgData[4]=(CfgData[1]+CfgData[2]+CfgData[3])&0xff;
IapProgram(0x04, CfgData[4]);//写入校验
IapProgram(0x00, 0xa5);//写入标识
}
#define UPDATE_INTERVAL 0xFF
void ReadCfg(void)
{
unsigned char i=0;
CfgData[0]=IapRead(0x00); //标识 0xa5
if(CfgData[0]==0xa5)
{
for (i=1;i<91;i++){ //读多个数据
CfgData[i]=IapRead(i);
}
}
//使用默认参数
CfgData[1]=0x05; //亮度
CfgData[2]=UPDATE_INTERVAL>>8;
CfgData[3]=UPDATE_INTERVAL&0xff;//校时周期
}
2.6 时钟、定时器驱动程序
// 时钟底层驱动函数
定时器0底层驱动函数
定时器2底层驱动函数
// 底层配置程序 ---------------------------------------------------------------------------------------------------------------
void SystemClock_Config(void)
{
P_SW2 = 0x80;
XOSCCR = 0xc0; //启动外部晶振
while (!(XOSCCR & 1)); //等待时钟稳定
CLKDIV = 0x00; //时钟不分频
CKSEL = 0x01; //选择外部晶振
P_SW2 = 0x00;
}
void TM2_Baud_Init(void)//定时器2做串口1,2,3,4通用波特率发生器,优先级固定为最低优先级0
{
//固定定时器2做串口1,2,3,4通用波特率发生器,优先级固定为最低优先级0
AUXR &= (~(T2R | T2x12));
AUXR |= (T2R | T2x12); //启动定时器2,定时器2以系统不分频,定时器2做串口1波特率发生器
INTCLKO &= (~T2CLKO); //中断与时钟输出控制寄存器INTCLKO(不可位访问),关闭定时器2时钟输出
//TM2PS //定时器2的8位预分频寄存器(TM2PS),默认为0 定时器2时钟=系统时钟SYSCLK/(TM2PS+1)
T2H = (-SYSCLK / UART2_BPR / 4) >> 8;
T2L = (-SYSCLK / UART2_BPR / 4); //65536-11059200/115200/4=0FFE8H
}
void TM0_Init(unsigned char pri) //定时器0、1可设优先级,定时器2、3、4固定为最低优先级0,最高为3
{
//定时器0 初始化 系统时钟12分频,模式0自动重载的16位定时器
TMOD &= 0xf0; //定时器0/1模式寄存器TMOD(不可位访问),定时器0,模式0(16位自动重载模式)
AUXR &= (~T0x12); //辅助寄存器1 AUXR(不可位访问),定时器0系统12分频
AUXR |=T0x12; //辅助寄存器1 AUXR(不可位访问),定时器0系统不分频
INTCLKO &= (~T0CLKO); //中断与时钟输出控制寄存器INTCLKO(不可位访问),关闭定时器0时钟输出
TH0 = 0x28; //11.0592M/200hz=55296;//65536-55296 =10240(0x2800)
TL0 = 0x02;
PT0 = pri & 0x01; //定时器中断优先级PT0H,PT0:PT0=1 11=3 最高优先级
IPH &= (~PT0H); //无法按位操作
IPH |= (pri & PT0H); //PT0H=1
TR0 = 1; //定时器0/1、外部中断0/1控制寄存器TCON(可位访问),启动定时器0 不能修改TH0和TH1的值,会改变定时器周期
ET0 = 1; //中断使能寄存器IE(可位访问) 使能定时器0中断
}
2.7 定时器跑秒程序
// 定时器跑秒函数
获取秒函数
获取毫秒函数
获取微秒函数
#define MS_TICK 5 //最大间隔5ms(200HZ),否则需调整12分频,避免溢出
#define cpu_on() P26=0
#define cpu_off() P26=1
static volatile unsigned long idata t_utc;//从1970年开始的时间秒数
static volatile unsigned int idata mscnt=0;//使用volatile,不优化,每次都更新寄存器值
void Time_Update(void)
{
systimer+=MS_TICK; //= SYSTEMTICK_PERIOD_MS;
}
// 中断回调程序 -------------------------
void Time_Update_Callback(void)
{
mscnt+=MS_TICK;
if(mscnt>=1000) //跑秒
{
mscnt=0;
t_utc++;
cpu_on();
}
else if(mscnt>=500) //使能读QCCLK
{
cpu_off();
}
Time_Update();
}
unsigned long GetUtcTime(void)//获取绝对标准UTC时间的总秒数,从1970开始
{
return t_utc;
}
unsigned long GetMsTime(void)//获取当前毫秒数
{
return mscnt;
}
unsigned long GetUsTime(void)//获取当前微秒数
{
unsigned long xdata t;
t=TH0;
t<<=8;
t+=TL0;
t=65536-t;//读取定时器值
t=(t*5000)/4608;//11.0592M/200hz/12=4608;//65536-4608 =60928(0xee00)
t+= ((unsigned long)mscnt*1000);
return t;
}
2.8 MAX7129驱动程序
// 数码管驱动函数
//------------------------------------------------------------------------------------
//-- DESCRIPTION : BIN to seven segments converter
//-- segment encoding
//-- e
//-- +---+
//-- f | | d
//-- +---+ <- g
//-- a | | c
//-- +---+
//-- b
//-- Outputs (data_out) active : high
//-- .,a,b,c,d,e,f,g -->(bit7~bit0)
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
//-- DESCRIPTION : BIN to seven segments converter HS210801K-16
//-- segment encoding
//-- a
//-- +---+
//-- f | | b
//-- +---+ <- g
//-- e | | c
//-- +---+
//-- d
//-- Outputs (data_out) active : low
//-- .,g,f,e,d,c,b,a -->(bit7~bit0)
//------------------------------------------------------------------
//-- Outputs (data_out) active : high MAX7219 共阴,高有效
//-- .,a,b,c,d,e,f,g -->(bit7~bit0)
//----------------------------------------------------------------------------------
//MAX7219 --VCC GND CLK CS DATA 对应SZZ40-SFM-NB1.0
#define CLK_Hi() P21 = 1 //高,CLK上升沿数据被移入内部移位寄存器,下降沿从DOUT移出 一次称一位
#define CLK_Lo() P21 = 0 //低,CLK下降沿数据从DOUT移出 一次称一位
#define CS_Hi() P22 = 1 //高,CS上升沿锁存以上移位进输入的最后16位数据 MAX7219为LOAD MAX7221为CS,只有在CS为低选通时,CLK输入才有效
#define CS_Lo() P22 = 0 //低,CS置低选通 MAX7219,串行数据载入移位寄存器 MAX7219为LOAD MAX7221为CS,只有在CS为低选通时,CLK输入才有效
#define DIN_Hi() P23 = 1 //高,DIN,数据位输入高
#define DIN_Lo() P23 = 0 //低,DIN,数据位输入低
#define Delay() _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
/*定义MAX7219寄存器 ******************************************************************/
#define REG_NO_OP 0x00 // 定义空操作 register
#define DIG_1 0x01 // 定义数码管1 register
#define DIG_2 0x02 // 定义数码管2 register
#define DIG_3 0x03 // 定义数码管3 register
#define DIG_4 0x04 // 定义数码管4 register
#define DIG_5 0x05 // 定义数码管5 register
#define DIG_6 0x06 // 定义数码管6 register
#define DIG_7 0x07 // 定义数码管7 register
#define DIG_8 0x08 // 定义数码管8 register
#define REG_DECODE 0x09 // 定义解码控制 register
#define REG_INTENSITY 0x0a // 定义显示亮度 register
#define REG_SCAN_LIMIT 0x0b // 定义扫描限制 register
max7219共阴极 对应显示段表 ([0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [A], [b], [C], [d], [E], [F], blank) ***********************************************************/
unsigned char code code_table[17]= {0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b,0x77,0x1f,0x4e,0x3d,0x4f,0x47,0x00}; /*采用数组*/
/****************************************************************** * MAX7219_Send()描述: 向MAX7219传送一字节数据
Arguments : dataout = data to send
Returns : none ******************************************************************/
void send (unsigned char datain)
{
unsigned char i,temp;
for (i=8; i>0; i--)
{
CLK_Lo(); // CLK 置低
temp=datain&0x80;
if (temp==0x80) // 判断并输出一位
DIN_Hi(); // 输出"1"
else // 或
DIN_Lo(); // 输出"0"
datain<<=1; //datain左移位,以便再次与0x80按位与
CLK_Hi(); // CLK 置高
}
}
/**************************************************************** * MAX7219_Write()/MAX7219_Write_1()描述: 向 MAX7219 写命令
Arguments : reg_number = register to write to
dataout = data to write to MAX7219
Returns : none ************************************************************** */
void MAX7219_Write (unsigned char add1, unsigned char dat1) //向第一片MAX7219写数据
{
CS_Lo(); // CS置低选通 MAX7219
send(add1); // 写register number 到 MAX7219
send(dat1); // 写 data 到 MAX7219
CS_Hi(); // 利用CS上升沿锁存以上移位进输入的16位数据
}
void MAX7219_Write_12 (unsigned char add1, unsigned char dat1,unsigned char add2, unsigned char dat2) //向两片MAX7219写数据
{
CS_Lo(); // CS置低选通 MAX7219
send(add2); // 写register number 到 第一片MAX7219
send(dat2); // 写 data 到 第一片MAX7219
send(add1); // 写register number 到 第一片MAX7219
send(dat1); // 写 data 到 第一片MAX7219
CS_Hi(); // 利用CS上升沿锁存以上移位进输入的16位数据
}
/******************************************************************** MAX7219_DisplayChar()描述: 使某一位显示一个数字
Arguments : digit = digit number (0-7)
character = character to display (0-9, A-Z)
dp = dp to display (0, 0x80)
Returns : none ****************************************************************/
void MAX7219_DisplayChar (unsigned char digit,unsigned char character,unsigned char dp)
{
MAX7219_Write((digit+1), code_table[character&0x0f]|dp);
}
//PS:这个函数可以不要,直接调用写数据函数就可以了(原版)
/******************************************************************** MAX7219_Clear()/MAX7219_clear_1()描述: 清除所有位的显示
Arguments : none
Returns : none *****************************************************************/
void MAX7219_Clear (void)
{
unsigned char i;
for (i=0; i < 8; i++)MAX7219_Write(i, 0x00); // 清除第一片MAX7219所有位的显示
}
/********************************************************************
MAX7219_SetBrightness()描述: 设置数码管显示亮度
Arguments : brightness (0-15)
Returns : none *****************************************************************/
void MAX7219_SetBrightness (unsigned char brightness)
{
brightness &= 0x0f; // 屏蔽高位字节
MAX7219_Write(REG_INTENSITY, brightness); // 设置数码管显示亮度
}
/******************************************************************** MAX7219_DisplayTestStop()描述: 退出 test 模式
Arguments : none
Returns : none ***************************************************************/
void MAX7219_DisplayTestStop (void)
{
MAX7219_Write(REG_DISPLAY_TEST, 0); //置 MAX7219为正常显示模式
}
/********************************************************************
MAX7219_ShutdownStop()描述: 退出 shutdown 模式
Arguments : none
Returns : none ****************************************************************/
void MAX7219_ShutdownStop (void)
{
MAX7219_Write(REG_SHUTDOWN, 1); //置MAX7219为正常显示模式
}
/******************************************************************** MAX7219_Init() 描述: MAX7219初始化模块,应该先于其他MAX7219函数而被调用
Arguments : none
Returns : none *****************************************************************/
void Max7219_Reset (void)
{
//设置为全显示0~7 DIG 减小扫描位数,增加扫描率,亮度功率增加,显示小于3位时,要设置ISET电阻来限制最大电流,避免单个DIG电流过大。
MAX7219_Write(REG_SCAN_LIMIT, 7);
MAX7219_Write(REG_DECODE, 0x00); //所有位设置为非解码方式
MAX7219_ShutdownStop(); //置MAX7219为(非关断)正常显示模式
MAX7219_DisplayTestStop(); //置MAX7219为(非test)正常显示模式
MAX7219_SetBrightness((CfgData[1]*3)&0x0f); //设置数码管显示亮度
}
2.9 MAX7129显示程序
// 数码管显示函数
void MAX7219_ClearChar (void)
{
unsigned int i=0;
for(i=0;i<8;i++)
{
MAX7219_Write(i+1,CODE_BLANK);
}
}
/******************************************************************** MAX7219_DisplayTestStart()描述: 进入 test 模式
Arguments : none
Returns : none ****************************************************************/
void MAX7219_DisplayTestStart (void)
{
MAX7219_Write(REG_DISPLAY_TEST, 1); //置MAX7219为 test 模式
}
void MAX7219_DisplayTime (struct ctm t)
{
//根据显示实际调整第一个参数的数值
MAX7219_DisplayChar(8,2,0);
MAX7219_DisplayChar(9,0,0);
MAX7219_DisplayChar(10,(t.tm_year%100)/10,0);
MAX7219_DisplayChar(11,t.tm_year %10,0);
MAX7219_DisplayChar(12,(t.tm_mon+1)/10,0);
MAX7219_DisplayChar(13,(t.tm_mon+1) %10,0);
MAX7219_DisplayChar(14,t.tm_mday/10,0);
MAX7219_DisplayChar(15,t.tm_mday %10,0);
MAX7219_DisplayChar(0,t.tm_hour/10,0);
MAX7219_DisplayChar(1,t.tm_hour %10,0x80);
MAX7219_DisplayChar(2,t.tm_min/10,0);
MAX7219_DisplayChar(3,t.tm_min %10,0x80);
MAX7219_DisplayChar(4,t.tm_sec/10,0);
MAX7219_DisplayChar(5,t.tm_sec %10,0);
}
#define TASKS_HOLD 100
void Task_Max7219(unsigned int tk)
{
static unsigned char index=0;
static unsigned long xdata lt = 0;
unsigned long xdata ut = 0;
ut = GetMsTime(); //一毫秒一次循环
if(ut >= tk && ut < (tk + TASKS_HOLD)) //按ms的时序开始,tk 为0则立即更新
{
ut = GetUtcTime();//一秒一次循环
if(ut != lt) //每秒更新一次
{
lt = ut;
switch (index)
{
case 0:
Max7219_Reset();
MAX7219_DisplayTestStart();
break;
case 1:
case 2:
break;
case 3:
MAX7219_DisplayTestStop(); //置MAX7219为正常显示模式
MAX7219_Clear(); //清除所有位的显示
MAX7219_DisplayVer();
break;
default:
MAX7219_DisplayTime(c_lct);
}
if(index<100)index++;
}
}
}
2.10 无线通信模块程序
// 函数
#define GET get_uart2
#define PUT send_uart2
//有人WH-LTE-7S1-------------------------------
unsigned char code ATE0[] = "usr.cn#AT+E=OFF\r\n";
unsigned char code AT_CSQ[] = "usr.cn#AT+CSQ\r\n";
unsigned char code AT_IMEI[] = "usr.cn#AT+IMEI?\r\n";
unsigned char code AT_ICCID[] = "usr.cn#AT+ICCID?\r\n";
unsigned char code AT_LBS[] = "usr.cn#AT+LBS?\r\n";
unsigned char code AT_LBS2[] = "usr.cn#AT+LBS=2\r\n";
unsigned char code AT_CCLK[] = "usr.cn#AT+CCLK?\r\n";
unsigned char code AT_SOCKA_R[] = "usr.cn#AT+SOCKA?\r\n";
unsigned char code AT_SOCKA_W[] = "usr.cn#AT+SOCKA=";
unsigned char code CFG_SOCKA[] = "UDP,ntp.(获取时间网站).net,123\r\n";
unsigned char code AT_SOCKAEN_R[] = "usr.cn#AT+SOCKAEN?\r\n";
unsigned char code AT_SOCKAEN_W[] = "usr.cn#AT+SOCKAEN=ON\r\n";
unsigned char code AT_SHORTATM_W[] = "usr.cn#AT+SHORTATM=120\r\n";
unsigned char code AT_SOCKB_R[] = "usr.cn#AT+SOCKB?\r\n";
unsigned char code AT_SOCKB_W[] = "usr.cn#AT+SOCKB=";
unsigned char code CFG_SOCKB[] = "UDP,iot.(获取时间网站).net,端口号\r\n";
unsigned char code AT_SOCKBEN_R[] = "usr.cn#AT+SOCKBEN?\r\n";
unsigned char code AT_SOCKBEN_W[] = "usr.cn#AT+SOCKBEN=ON\r\n";
unsigned char code AT_SHORTBTM_W[] = "usr.cn#AT+SHORTBTM=120\r\n";
unsigned char code AT_HEARTEN_R[] = "usr.cn#AT+HEARTEN?\r\n";
unsigned char code AT_HEARTEN_W[] = "usr.cn#AT+HEARTEN=OFF\r\n";
unsigned char code AT_STMSG_R[] = "usr.cn#AT+STMSG?\r\n";
unsigned char code AT_STMSG_W[] = "usr.cn#AT+STMSG=chijiu_iot21_001\r\n";
unsigned char code AT_CACHEN_R[] = "usr.cn#AT+CACHEN?\r\n";
unsigned char code AT_CACHEN_W[] = "usr.cn#AT+CACHEN=OFF\r\n";
unsigned char code AT_SDPEN_R[] = "usr.cn#AT+SDPEN?\r\n";
unsigned char code AT_SDPEN_W[] = "usr.cn#AT+SDPEN=ON\r\n";
unsigned char code AT_S[] = "usr.cn#AT+S\r\n";
static int p_write(unsigned char* buf, int len)//用于统一发送数据格式,其中buf不能是ptx发送缓存
{
if(len>0)
{
memset(ptx, 0, TX_LEN);//清空发送缓存
memcpy (ptx, buf, len);//通一发送数据类型和指针类型
PUT(ptx,len);
}
return len;
}
static int p_read(unsigned char* buf)
{
int idata len=0;
len=GET(buf);
return len;
}
static void get_sdpen(void)
{
p_write((unsigned char*)AT_SDPEN_R,strlen(AT_SDPEN_R));
}
static void get_sig(void)
{
p_write((unsigned char*)AT_CSQ,strlen(AT_CSQ));
}
static void get_imei(void)
{
p_write((unsigned char*)AT_IMEI,strlen(AT_IMEI));
}
static void get_iccid(void)
{
p_write((unsigned char*)AT_ICCID,strlen(AT_ICCID));
}
static void get_lbs(void)
{
p_write((unsigned char*)AT_LBS,strlen(AT_LBS));
}
static void get_lbs2(void)
{
p_write((unsigned char*)AT_LBS2,strlen(AT_LBS2));
}
static void cat_config(void)
{
int len0,len1=0;
p_write((unsigned char*)ATE0,strlen(ATE0));//关回显
delay_ms(100);
memset(ptx, 0, TX_LEN);//清空发送缓存
len0=strlen(AT_SOCKA_W);
memcpy (ptx, (unsigned char*)AT_SOCKA_W, len0);//通一发送数据类型和指针类型
len1=strlen(CFG_SOCKA);
memcpy (ptx+len0, (unsigned char*)CFG_SOCKA, len1);//通一发送数据类型和指针类型
PUT(ptx,len0+len1);
delay_ms(100);
p_write((unsigned char*)AT_SOCKAEN_W,strlen(AT_SOCKAEN_W));//设置SOCKA启用
delay_ms(100);
p_write((unsigned char*)AT_SHORTATM_W,strlen(AT_SHORTATM_W));//设置SOCKA短链接时长
delay_ms(100);
memset(ptx, 0, TX_LEN);//清空发送缓存
len0=strlen(AT_SOCKB_W);
memcpy (ptx, (unsigned char*)AT_SOCKB_W, len0);//通一发送数据类型和指针类型
len1=strlen(CFG_SOCKB);
memcpy (ptx+len0, (unsigned char*)CFG_SOCKB, len1);//通一发送数据类型和指针类型
PUT(ptx,len0+len1);
delay_ms(100);
p_write((unsigned char*)AT_SOCKBEN_W,strlen(AT_SOCKBEN_W));//设置SOCKB启用
delay_ms(100);
p_write((unsigned char*)AT_SHORTBTM_W,strlen(AT_SHORTBTM_W));//设置SOCKB短链接时长
delay_ms(100);
p_write((unsigned char*)AT_HEARTEN_W,strlen(AT_HEARTEN_W));//设置心跳关闭
delay_ms(100);
p_write((unsigned char*)AT_CACHEN_W,strlen(AT_CACHEN_W));//设置串口缓存关闭
delay_ms(100);
p_write((unsigned char*)AT_SDPEN_W,strlen(AT_SDPEN_W));//设置套节字分发开启
delay_ms(100);
p_write((unsigned char*)AT_S,strlen(AT_S));
}
static void socka( char* buf)
{
char *q;
char *p;
q=buf;
//p=strstr(q,"SOCKA:UDP,ntp.zhonglianwang.net,123\r\n");//设置SOCKA地址 //如果修改,上边设置参数判读时也必须修改
p=strstr(q,CFG_SOCKA);
if(p==NULL)
{
initialized=2;//复位重置
}
}
static void sockb( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,CFG_SOCKB);
if(p==NULL)
{
initialized=2;//复位重置
}
}
static void sockaen( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,"SOCKAEN:OFF\r\n");//设置SOCKA启用
if(p!=NULL)
{
initialized=2;//复位重置
}
}
static void sockben( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,"SOCKBEN:OFF\r\n");//设置SOCKB启用
if(p!=NULL)
{
initialized=2;//复位重置
}
}
static void hearten( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,"HEARTEN:ON\r\n");//设置心跳关闭
if(p!=NULL)
{
initialized=2;//复位重置
}
}
static void cachen( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,"CACHEN:ON\r\n");//设置串口缓存关闭
if(p!=NULL)
{
initialized=2;//复位重置
}
}
static void sdpen( char* buf)
{
char *q;
char *p;
q=buf;
p=strstr(q,"SDPEN:ON\r\n");
if(p!=NULL)
{
if(initialized!=2)
{
initialized=1;//初始化成功
ltdl=0;
}
}
else
{
p=strstr(q,"SDPEN:OFF\r\n");//设置套节字分发开启
if(p!=NULL)
{
initialized=2;//复位重置
}
}
}
void socket_send(unsigned char *buf,unsigned int len,unsigned char ch)//0~3
{
//套接字协议
}
void socket_receive(unsigned char *buf,unsigned int len)//0~3
{
//套接字协议
}
static void rec_pro(unsigned char* buf,int len)
{
char *q;
q=strstr((char*)buf,"+CSQ:");//\r\n+CSQ: 31, 99\r\n\r\nOK\r\n
if(q!=NULL)csq(q);//+CSQ: 31, 99\r\n\r\nOK\r\n
// q=strstr((char*)buf,"+CCLK:");//\r\n+CCLK: “20/06/19,20:05:19+32”\r\n\r\nOK\r\n
// if(q!=NULL)cclk(q);
q=strstr((char*)buf,"chijiu");//\r\n+IMEI:864333040712457\r\n\r\nOK\r\n
if(q!=NULL)chijiu(q);
q=strstr((char*)buf,"+ICCID:");//\r\n+ICCID:89860621240067311755\r\n\r\nOK\r\n
if(q!=NULL)iccid(q);
q=strstr((char*)buf,"+IMEI:");//\r\n+IMEI:864333040712457\r\n\r\nOK\r\n
if(q!=NULL)imei(q);
q=strstr((char*)buf,"+LBS:");//\r\n+LBS: LNG = 114.43350220, LAT = 30.49159431, TIME = 2020-12-11 15:45:39, ADDINFO: 武汉市高新大道426号\r\n\r\nOK\r\n
if(q!=NULL)lbs(q);
q=strstr((char*)buf,"+SOCKA:");//\r\n+SOCKA:<TCP,UDP>,<1~100 bytes>,<1~65535>
if(q!=NULL)socka(q);
q=strstr((char*)buf,"+SOCKAEN:");//\r\n+SOCKAEN:ON\r\n\r\nOK\r\n
if(q!=NULL)sockaen(q);
q=strstr((char*)buf,"+SOCKB:");//\r\n+SOCKB:<TCP,UDP>,<1~100 bytes>,<1~65535>
if(q!=NULL)sockb(q);
q=strstr((char*)buf,"+SOCKBEN:");//\r\n+SOCKBEN:ON\r\n\r\nOK\r\n
if(q!=NULL)sockben(q);
q=strstr((char*)buf,"+HEARTEN:");//\r\n+HEARTEN:OFF\r\n\r\nOK\r\n
if(q!=NULL)hearten(q);
q=strstr((char*)buf,"+CACHEN:");//\r\n+CACHEN:OFF\r\n\r\nOK\r\n
if(q!=NULL)cachen(q);
q=strstr((char*)buf,"+SDPEN:");//\r\n+SDPEN:ON\r\n\r\nOK\r\n
if(q!=NULL)sdpen(q);
socket_receive(buf,len);
}
#define cat1_on() P14=1
#define cat1_off() P14=0
void Init_Cat(void)
{
cat1_on();
}
void Task_Cat(unsigned int tk)
{
static unsigned long idata lt = 0;
static unsigned char idata lm = 0;
unsigned long idata ut = 0;
unsigned int idata usCRC=0;
int idata len=0;
len=p_read(prx);
if(len>0)
{
rec_pro(prx,len);
if(cmd_en==1)
{
cmd_en=0;
ut=clk_packet(upBuf);第一个客体包(1时间)
ut=clk_packet_add(upBuf,ut,prx,len,18);//ADDR
socket_send(upBuf,ut,1);
}
}
ut = GetMsTime();
if(ut >= (tk + dl_index) && ut < (tk + TASKS_HOLD + dl_index)) //按ms的时序开始,tk 为0则立即更新,
{
ut = GetUtcTime();
if(ut != lt) //每秒更新一次
{
lt = ut;
//执行TASK---------------------------
if(ltdl<(((unsigned int)CfgData[2]<<8)|CfgData[3]))ltdl++;
else
{
ltdl=0;
if(lm<48)lm++;//每(48*校时周期)后,上传输一次地理信息
else lm=0;
}
if(initialized==2 || initialized==0)
{
if((ltdl&0x1f)==0x10)get_imei();
else if((ltdl&0x1f)==0x11)p_write((unsigned char*)AT_STMSG_R,strlen(AT_STMSG_R));//查询启动信息
else if((ltdl&0x1f)==0x12)p_write((unsigned char*)AT_SOCKA_R,strlen(AT_SOCKA_R));//查询SOCKA地址
else if((ltdl&0x1f)==0x13)p_write((unsigned char*)AT_SOCKAEN_R,strlen(AT_SOCKAEN_R));//查询SOCKA启用
else if((ltdl&0x1f)==0x14)p_write((unsigned char*)AT_SOCKB_R,strlen(AT_SOCKB_R));//查询SOCKB地址
else if((ltdl&0x1f)==0x15)p_write((unsigned char*)AT_SOCKBEN_R,strlen(AT_SOCKBEN_R));//查询SOCKB启用
else if((ltdl&0x1f)==0x16)p_write((unsigned char*)AT_HEARTEN_R,strlen(AT_HEARTEN_R));//查询心跳关闭
else if((ltdl&0x1f)==0x17)p_write((unsigned char*)AT_CACHEN_R,strlen(AT_CACHEN_R));//查询串口缓存关闭
else if((ltdl&0x1f)==0x18)get_iccid();
else if((ltdl&0x1f)==0x19)get_sdpen();//查询套节字分发开启
else if((ltdl&0x1f)==0x1a)
{
if(initialized==2)
{
initialized=0; //0:未初始化,1:初始化成功,2;复位重置,3;校時成功
cat_config();
ltdl=0;
}
}
}
else
{
ut=GetNtpSync();
//数据上传时刻----
if((ltdl&0xffff)==0x12)get_lbs();
else if((ltdl&0xffff)==0x13)get_sig(); //一天1M数据,一分钟不超694字节(往返),32秒一次上传数据(数据最好不超过108字节)(20+8+77),64秒一次NTP(20ip头+8UDP头+48数据=76,76*2=152字节)
else if((ltdl&0xffff)==0x2C)//UPDATA
{
len=clk_packet(upBuf);第一个客体包(1时间)
len=clk_packet_add(upBuf,len,prx,5,16);//客体16--子钟--驱动(状态)
socket_send(upBuf,len,1);
if(GetSyncOK()==0x01)
{
if(initialized==1)
{
ltdl=dl_index;//初始化校时成功后,根据IMEI号差开时序
initialized=3;
}
}
}
else if((ltdl&0xff)==0x00)//NTP 同步周期固定为48~256秒//数据NTP同步时刻-首次链接,延时大------
{
if(GetSyncOK()!=1){ //第一次NTP同步本地时间后将ntp_en一直为1
ntp_en=0;
}else{
ntp_en=1;
}
construct_packet(upBuf);//数据包长48
socket_send(upBuf,48,0);
}
else if((ltdl&0xff)==0x07 || (ut!=0x01 && (ltdl&0x07)==0x07) && (ltdl&0xff)<=SYNCPRE_MIN)//NTP 同步周期固定为48~256秒 次数大于NTP的SYNC_MAX
{
ntp_en=1;
construct_packet(upBuf);//数据包长48
socket_send(upBuf,48,0);
check_clk();
}
else if((ltdl&0xffff)==0x0011)
{
if(lm==2)get_lbs2();//数据获取地理位置时刻--
}
}
}
}
}
总结
上述程序中并未完全给出,但是思路没问题。