打印
[STC单片机]

请教:STC15W204s比较器应用

[复制链接]
4765|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
STC110|  楼主 | 2019-5-29 18:15 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
沙发
叶春勇| | 2019-5-29 18:23 | 只看该作者
大把8脚带ad单片机,ht66f002。这个别折腾了一致性不好,还要校准。

使用特权

评论回复
板凳
hwpga| | 2019-5-29 20:10 | 只看该作者
本帖最后由 hwpga 于 2019-5-29 20:11 编辑
叶春勇 发表于 2019-5-29 18:23
大把8脚带ad单片机,ht66f002。这个别折腾了一致性不好,还要校准。

像我们随便写一个程序都是6K起步
一个ADC函数可能都要写1k差不多
就这种2k的ROM能拿来干什么
这还不如东软的芯片
东软的ES7P001还可以,就是烧录器有点小贵

使用特权

评论回复
地板
叶春勇| | 2019-5-29 21:19 | 只看该作者
本帖最后由 叶春勇 于 2019-5-29 21:25 编辑

楼上,8脚单片机,不可能搞复杂的东西,但是成本敏感。
你那个东软的单片机,什么价格。貌似还不错。

使用特权

评论回复
5
STC110|  楼主 | 2019-5-30 08:30 | 只看该作者
本帖最后由 STC110 于 2019-5-30 08:31 编辑
叶春勇 发表于 2019-5-29 18:23
大把8脚带ad单片机,ht66f002。这个别折腾了一致性不好,还要校准。

程序不多,主要考虑价格。我搜索下,以前没用过,下载电路应该都差不多吧?

使用特权

评论回复
6
叶春勇| | 2019-5-30 09:19 | 只看该作者
9毛多,要配个下载器

使用特权

评论回复
7
STC110|  楼主 | 2019-5-30 15:43 | 只看该作者
叶春勇 发表于 2019-5-30 09:19
9毛多,要配个下载器

下载可以使用232串口在线下载的吧,您那里有电路图参考下吗?它需要外部复位和时钟电路的吧?

使用特权

评论回复
8
coody| | 2019-5-30 16:13 | 只看该作者
STC官网有STC15系列库函数的例程,里面有“36-比较器做ADC-C语言”,效果挺好。将例程的P_ADC定义到MCU有的IO,并设置为推挽输出就OK。这种是用电荷平衡的方式做的ADC,在90年代买不到合适的ADC(或者会非常贵)、买不到合适的电荷平衡做的VFC,我就是用这种方式实现的,比如用MCU+LM339做4路VFC。


/****************************
本示例在Keil开发环境下请选择Intel的8052芯片型号进行编译

本例程MCU的工作频率为22.1184MHz.

使用MCU自带的比较器进行ADC转换, 并通过串口输出结果. 用定时器0产生10us中断查询比较器的状态.

使用比较器做ADC, 原理图如下.
做ADC的原理是基于电荷平衡的计数式ADC.
电压从Vin输入, 通过100K+104滤波, 进入比较器的P5.5正输入端, 经过比较器的比较, 将结果输出到P1.5再通过100K+104滤波后送比较器P5.4负输入端,跟输入电压平衡.
设置两个变量: 计数周期(量程)adc_duty 和 比较结果高电平的计数值 adc, adc严格比例于输入电压.
ADC的基准就是P1.5的高电平. 如果高电平准确,比较器的放大倍数足够大,则ADC结果会很准确.
当比较结果为高电平,则P1.5输出1, 并且adc+1.
当比较结果为低电平,则P1.5输出0.
每一次比较都判断计数周期是否完成,完成则adc里的值就是ADC结果.
电荷平衡计数式ADC的性能类似数字万用表用的双积分ADC, 当计数周期为20ms的倍数时,具有很强的抗工频干扰能力,很好的线性和精度.
原理可以参考ADD3501(3 1/2位数字万用表)或ADD3701(3 3/4位数字万用表), 也可以参考AD7740 VFC电路.

例: 比较一次的时间间隔为10us, 量程为10000, 则做1次ADC的时间为100ms. 比较器的响应时间越短, 则完成ADC就越快.

由于要求每次比较时间间隔都要相等,所以用C编程最好在定时器中断里进行, 定时器设置为自动重装, 高优先级中断, 其它中断均低优先级.
用汇编的话, 保证比较输出电平处理的时间要相等.


                                         100K
                            /| P5.5       ___
                    P1.2   /+|---------o-|___|- ------- Vin
                     .----<  | P5.4    |
                     |     \-|---.     |
                     |      \|   |     |
                     |           |     |
                     |    ___    |     |
                     '---|___|---o     |
                        100K     |     |
                                ---   ---
                                ---   ---
                            104  |     |  104
                                 |     |
                                ===   ===
                                GND   GND



******************************/

#define MAIN_Fosc                22118400L        //定义主时钟
#define        BaudRate1                9600ul                //定义波特率
#define        ADC_SCALE                50000                //ADC满量程, 根据需要设置

#include        "STC15Fxxxx.H"


/*************        本地常量声明        **************/

//CMPCR1
#define        CMPEN        0x80        //1: 允许比较器, 0: 禁止,关闭比较器电源
#define        CMPIF        0x40        //比较器中断标志, 包括上升沿或下降沿中断, 软件清0
#define        PIE                0x20        //1: 比较结果由0变1, 产生上升沿中断
#define        NIE                0x10        //1: 比较结果由1变0, 产生下降沿中断
#define        PIS                0x08        //输入正极性选择, 0: 选择内部P5.5做正输入,           1: 由ADCIS[2:0]所选择的ADC输入端做正输入.
#define        NIS                0x04        //输入负极性选择, 0: 选择内部BandGap电压BGv做负输入, 1: 选择外部P5.4做输入.
#define        CMPOE        0x02        //1: 允许比较结果输出到P1.2, 0: 禁止.
#define        CMPRES        0x01        //比较结果, 1: CMP+电平高于CMP-,  0: CMP+电平低于CMP-,  只读

//CMPCR2
#define        INVCMPO        0x80        //1: 比较器输出取反,  0: 不取反
#define        DISFLT        0x40        //1: 关闭0.1uF滤波,   0: 允许
#define        LCDTY        0x00        //0~63, 比较结果变化延时周期数

#define        TIM_16BitAutoReload                        0
#define        TIM_16Bit                                        1
#define        TIM_8BitAutoReload                        2
#define        TIM_16BitAutoReloadNoMask        3

#define        Pin0                0x01        //IO引脚 Px.0
#define        Pin1                0x02        //IO引脚 Px.1
#define        Pin2                0x04        //IO引脚 Px.2
#define        Pin3                0x08        //IO引脚 Px.3
#define        Pin4                0x10        //IO引脚 Px.4
#define        Pin5                0x20        //IO引脚 Px.5
#define        Pin6                0x40        //IO引脚 Px.6
#define        Pin7                0x80        //IO引脚 Px.7
#define        PinAll                0xFF        //IO所有引脚

/*************        本地变量声明        **************/
//sbit        P_ADC        = P1^2;        //P1.2 比较器转IO输出端
sbit        P_ADC        = P1^4;        //P1.2 比较器转IO输出端
u16                adc;                        //ADC中间值, 用户层不可见
u16                adc_duty;                //ADC计数周期, 用户层不可见
u16                adc_value;                //ADC值, 用户层使用
bit                adc_ok;                        //ADC结束标志, 为1则adc_value的值可用. 此标志给用户层查询,并且清0


/*************        本地函数声明        **************/
void        TxString(u8 *puts);






void main(void)
{
        u8        i;
        u8        tmp[5];


//IO口初始化
//        P1n_push_pull(Pin2);                //P1.2设置为push-pull output
        P1n_push_pull(Pin4);                //P1.2设置为push-pull output
        P5n_pure_input(Pin4+Pin5);        //P5.4 P5.5设置为高阻输入


//比较器初始化
        CMPCR1 = 0;
        CMPCR2 = 20;                //比较结果变化延时周期数, 0~63
        CMPCR1 |= CMPEN;        //允许比较器                ENABLE,DISABLE
//        CMPCR1 |= PIE;                //允许上升沿中断        ENABLE,DISABLE
//        CMPCR1 |= NIE;                //允许下降沿中断        ENABLE,DISABLE
//        CMPCR1 |= PIS;                //输入正极性选择, 0: 选择内部P5.5做正输入,           1: 由ADCIS[2:0]所选择的ADC输入端做正输入.
        CMPCR1 |= NIS;                //输入负极性选择, 0: 选择内部BandGap电压BGv做负输入, 1: 选择外部P5.4做输入
//        CMPCR1 |= CMPOE;        //允许比较结果输出到P1.2,   ENABLE,DISABLE
//        CMPCR2 |= INVCMPO;        //比较器输出取反,         ENABLE,DISABLE
        CMPCR2 |= DISFLT;        //内部0.1uF滤波,          ENABLE,DISABLE


//定时器0 初始化
        TMOD &= ~0x0f;
        Timer0_16bitAutoReload();        //设置为16位自动重装模式
        Timer0_1T();        //设置为1T模式
        ET0 = 1;                //允许中断
        PT0 = 1;                //高优先级中断
        TH0 = (u8)((65536 - MAIN_Fosc / 100000ul)>>8);                //重装值        100KHZ, 10us,        65536 - (MAIN_Fosc)/100000
        TL0 = (u8)( 65536 - MAIN_Fosc / 100000ul);
        TR0 = 1;                //开始运行


//串口1初始化
        S1_USE_P30P31();        //UART1 使用P30 P31口        默认
//        S1_USE_P36P37();        //UART1 使用P36 P37口
//        S1_USE_P16P17();        //UART1 使用P16 P17口

        S1_8bit();                        //8位数据,波特率可变
        S1_RX_Enable();                //允许接收
        S1_TXD_RXD_OPEN();        //将TXD与RXD连接中继断开        默认
        S1_BRT_UseTimer2();        //使用Timer2做波特率发生器
        ES = 0;                                //禁止中断, 使用查询发送

        Timer2_1T();        //Timer2 1T模式, 固定为16位自动重装
    T2L = (65536 - (MAIN_Fosc/4/BaudRate1));   //设置波特率重装值
    T2H = (65536 - (MAIN_Fosc/4/BaudRate1))>>8;
        Timer2_Run();        //允许定时器2计数

        EA = 1;                        //允许全局中断

        TxString("\r\n使用比较器做ADC例子\r\n");        //SUART1发送一个字符串
       

        while (1)
        {
                if(adc_ok)                //等待ADC结束
                {
                        adc_ok = 0;                                //清除ADC已结束标志
                        TxString("ADC = ");        //转十进制
                        tmp[0] = adc_value / 10000 + '0';
                        tmp[1] = adc_value % 10000 / 1000 + '0';
                        tmp[2] = adc_value % 1000 / 100 + '0';
                        tmp[3] = adc_value % 100 / 10 + '0';
                        tmp[4] = adc_value % 10 + '0';
                        for(i=0; i<4; i++)                //消无效0
                        {
                                if(tmp[i] != '0')        break;
                                tmp[i] = ' ';
                        }
                        for(i=0; i<5; i++)                //发串口
                        {
                                TI = 0;
                                SBUF = tmp[i];
                                while(!TI);
                                TI = 0;
                        }
                        TxString("\r\n");
                }
        }
}


void TxString(u8 *puts)                //发送一个字符串
{
    for (; *puts != 0;        puts++)           //遇到停止符0结束
        {
                TI = 0;
                SBUF = *puts;
                while(!TI);
                TI = 0;
        }
}


/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR
{
        if((CMPCR1 & CMPRES) == 0)        P_ADC = 0;        //比较器输出高电平
        else                                //P_ADC输出低电平, 给负输入端做反馈.
        {
                P_ADC = 1;                        //P_ADC输出高电平, 给负输入端做反馈.
                adc ++;        //ADC计数+1
        }

        if(--adc_duty == 0)                        //ADC周期-1, 到0则ADC结束
        {
                adc_duty = ADC_SCALE;        //周期计数赋初值
                adc_value = adc;                //保存ADC值
                adc = 0;                                //清除ADC值
                adc_ok = 1;                                //标志ADC已结束
        }
}


使用特权

评论回复
9
STC110|  楼主 | 2019-6-1 10:44 | 只看该作者
coody 发表于 2019-5-30 16:13
STC官网有STC15系列库函数的例程,里面有“36-比较器做ADC-C语言”,效果挺好。将例程的P_ADC定义到MCU有的 ...

您好,我用的SOP8封装的STC15W204S,比较器做AD,我的想法是自己定义个I/O口当比较器输出,然后读CMPRES的值送到这个管脚,把这个脚接到CMP-,这样可以实现吗?

使用特权

评论回复
10
STC110|  楼主 | 2019-6-6 15:40 | 只看该作者
**NT018 发表于 2019-6-6 13:44
楼主测试后给个回复哈

这样可以实现

使用特权

评论回复
11
andy520520| | 2020-12-7 13:09 | 只看该作者
hwpga 发表于 2019-5-29 20:10
像我们随便写一个程序都是6K起步
一个ADC函数可能都要写1k差不多
就这种2k的ROM能拿来干什么

你是世界就51和东软

东软压根就没有用过,用过不会发这种无脑的帖子

使用特权

评论回复
12
sanzi666| | 2021-1-4 20:09 | 只看该作者
用比较器做AD,是不是还要用查表来找到对应的值吗。
一直看不明白原理是什么

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

8

帖子

0

粉丝