本程序可将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;
}文章作者:沃航科技