13397158231   jevian_ma@worldflying.cn

基于stc8系列的计数器程序

2021-09-29 19:36:33

本程序可将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;
}


文章作者:沃航科技

优秀产品推荐:物联网IO控制器

上一篇:chrome自动测试工具Puppeteer功能介绍

下一篇:openwrt安装IKEv2教程

联系我们

  • 地址:武汉市东湖高新开发区光谷总部国际1栋2412室
  • QQ:932773931
  • 电话:027-59761089-806
  • 手机:13397158231
  • 邮箱:jevian_ma@worldflying.cn