本程序可将stc8作为独立的计数器使用,通过串口读取计数器的数据。目前看来,可使用于几乎所有的stc8系列单片机。
话不多说,上代码:
#include "stc8.h" #include "intrins.h" #include <string.h> // 工作频率为22.1184MHz // 脉冲信号输入口为P3.4口,读取与清零控制口为P3.0,P3.1。 #define FOSC 22118400UL #define BRT (256 - FOSC / 12 / 9600 / 32) #define JISHU 50000 #define MJISHU (65536 - JISHU) #define uint8_t unsigned char #define uint16_t unsigned short #define uint32_t unsigned long uint8_t status = 0; uint32_t timer_numH = 0; uint32_t timer_numL = 0; uint16_t crc_calc (uint16_t crc, uint8_t *file_buff, int size) { int i, j; for (i = 0 ; i < size ; i++) { // 循环计算每个数据 crc ^= file_buff[i]; // 将八位数据与crc寄存器亦或,然后存入crc寄存器 for (j = 0; j < 8; j++) { // 循环计算数据的 if (crc & 0x0001) { // 判断右移出的是不是1,如果是1则与多项式进行异或。 crc >>= 1; // 将数据右移一位 crc ^= 0xa001; // 与上面的多项式进行异或 } else { // 如果不是1,则直接移出 crc >>= 1; // 将数据右移一位 } } } return crc; } #define WT_30M 0x80 #define WT_24M 0x81 #define WT_20M 0x82 #define WT_12M 0x83 #define WT_6M 0x84 #define WT_3M 0x85 #define WT_2M 0x86 #define WT_1M 0x87 void IapIdle() { IAP_CONTR = 0; //关闭 IAP 功能 IAP_CMD = 0; //清除命令寄存器 IAP_TRIG = 0; //清除触发寄存器 IAP_ADDRH = 0x80; //将地址设置到非 IAP 区域 IAP_ADDRL = 0; } uint8_t IapRead(uint8_t addr) { uint8_t dat; IAP_CONTR = WT_24M; //使能 IAP 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(uint8_t addr, uint8_t dat) { IAP_CONTR = WT_24M; //使能 IAP 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(uint8_t addr) { IAP_CONTR = WT_24M; //使能 IAP 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 TM0_Isr() interrupt 1 { status |= 0x08; } void TM0Task() { uint32_t num; ET0 = 0; // 关闭定时器中断 num = timer_numL; timer_numL += JISHU; if (timer_numL < num) { timer_numH++; } IapErase(0x0000); IapProgram(0x0000, ~(timer_numH>>24)); IapProgram(0x0001, ~(timer_numH>>16)); IapProgram(0x0002, ~(timer_numH>>8)); IapProgram(0x0003, ~timer_numH); IapProgram(0x0004, ~(timer_numL>>24)); IapProgram(0x0005, ~(timer_numL>>16)); IapProgram(0x0006, ~(timer_numL>>8)); IapProgram(0x0007, ~timer_numL); ET0 = 1; // 使能定时器中断 } void UartIsr() interrupt 4 { if (RI) { RI = 0; status |= 0x02; } } void UartTask() { uint32_t numL, numH; uint16_t crc; uint8_t cmd, i; uint8_t buff[12]; ES = 0; // 关闭串口中断 cmd = SBUF; switch (cmd) { case 0x01: // 读计数器 buff[0] = 0x00; buff[1] = 0x01; numH = timer_numH; numL = timer_numL + (((uint16_t)TH0<<8)|((uint16_t)TL0&0x00ff)) - MJISHU; if (numL < timer_numL) { numH++; } buff[2] = numH>>24; buff[3] = numH>>16; buff[4] = numH>>8; buff[5] = numH; buff[6] = numL>>24; buff[7] = numL>>16; buff[8] = numL>>8; buff[9] = numL; crc = 0xffff; crc = crc_calc(crc, buff, 10); buff[10] = crc; buff[11] = crc>>8; for (i = 0 ; i < 12 ; i++) { SBUF = buff[i]; while(TI==0); TI=0; } break; case 0x02: // 计数器清零 TR0 = 0; // 关闭定时器 TL0 = MJISHU; TH0 = MJISHU>>8; timer_numH = 0; timer_numL = 0; IapErase(0x0000); TR0 = 1; // 开启定时器 buff[0] = 0x00; buff[1] = 0x02; crc = 0xffff; crc = crc_calc(crc, buff, 2); buff[2] = crc; buff[3] = crc>>8; for (i = 0 ; i < 4 ; i++) { SBUF = buff[i]; while(TI==0); TI=0; } break; } ES = 1; // 使能串口中断 } int main () { // 配置P3.1推挽输出,其他高阻输入 P3M0 = 0x02; P3M1 = ~0x02; P3 = 0xff; TMOD = 0x24;// T0模式0(16位自动重载模式),外部计数模式。 // T1模式2(8位自动重载模式) // 串口1使用定时器1作为波特率发生器 SCON = 0x50; // 8位可变波特率模式,接收使能 AUXR = 0x00; // 串口1选择T1,T1不倍频,T0不倍频 TL1 = BRT; TH1 = BRT; TI = 0; RI = 0; ES = 1; // 使能串口中断 TR1 = 1; // 使用T0作为计数器 TL0 = MJISHU; TH0 = MJISHU>>8; ET0 = 1; // 使能定时器中断 TR0 = 1; // 启动定时器 EA = 1; // 使能CPU中断 timer_numH = (~IapRead(0))&0xff; timer_numH = (timer_numH<<8)|((~IapRead(1))&0xff); timer_numH = (timer_numH<<8)|((~IapRead(2))&0xff); timer_numH = (timer_numH<<8)|((~IapRead(3))&0xff); timer_numL = (~IapRead(4))&0xff; timer_numL = (timer_numL<<8)|((~IapRead(5))&0xff); timer_numL = (timer_numL<<8)|((~IapRead(6))&0xff); timer_numL = (timer_numL<<8)|((~IapRead(7))&0xff); while(1) { if (status) { if (status & 0x02) { status &= ~0x03; UartTask(); } if (status & 0x08) { status &= ~0x09; TM0Task(); } } else { status |= 0x01; PCON = PD; // 进入掉电模式 } } return 0; }
文章作者:沃航科技