打印
[AVR单片机]

做了一个用按键触发的输入捕捉,计算计数次数的程序

[复制链接]
1316|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
黄喉|  楼主 | 2014-8-26 11:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
想实现按键触发的输入捕捉,计算计数次数。思路是:开发板刚上电,使能溢出中断和输入捕捉中断,然后等待第一次按键按下。如果第一次按键按下触发了输入捕捉中断,进入中断服务程序后把0写入PER1。然后等待第二次输入捕捉中断,当第二次输入捕捉中断到来时,关闭预分频,把计数值写入PER2,用PER2-PER1得到两次按键期间的计数值,若其中发生溢出count++。计算出数值以后显示在数码管上,但是实际工作时,数码管始终显示全0。求高手能帮忙看看,解决小弟这个超超超新人的困惑。感激不尽


/*
* capture.c
*
* Created: 2014-8-25 14:11:47
*  Author: Administrator
*/


#include <avr/io.h>
#define F_CPU 8000000UL
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char DuanMa[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
unsigned char WeiMa[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
       
volatile unsigned char TempData[8];
unsigned char count = 0;
volatile unsigned char num = 0;
volatile unsigned int PER1=0,PER2=0;
volatile unsigned long int PER = 0;

void led_init(void)
{
        DDRA = 0xff;
        DDRF |= (1 << 3);
       
        PORTA = 0xff;
        PORTF |= (1 << 3);
        PORTF &= ~(1 << 3);
}

void seg_init(void)
{
        DDRA = 0xff;
        DDRC = 0xff;
        DDRF |= (1 << 1) | (1 << 2);
       
        PORTC = 0xff;
        PORTF |= (1 << 1);
        PORTF &= ~(1 << 1);
       
        PORTA = 0xff;
        PORTF |= (1 << 2);
        PORTF &= ~(1 << 2);
}

void seg_display(unsigned char firstbit,unsigned char weishu) //数码管显示函数
{
        static unsigned char i;
        PORTC = 0xff; //数码管消隐
        PORTF |= (1 << 1);
        PORTF &= ~(1 << 1);
       
        PORTC = TempData[i];
        PORTF |= (1 << 1);
        PORTF &= ~(1 << 1);
       
        PORTA = WeiMa[i+firstbit];
        PORTF |= (1 << 2);
        PORTF &= ~(1 << 2);
        _delay_ms(1);
        i++;
        if(i == weishu)
        i = 0;
}

void portd_init(void)
{
        DDRD &= (0 << 4); //PD4设为输入口
        PORTD |= (1 << 4); //PD4输出高电平
}

void timer1_init(void)
{
        TCCR1A = 0x00; //设为普通模式
        TCCR1B |= (1 << ICNC1) | (0 << ICES1) | (0 << CS12) | (0 << CS11) | (0 << CS10); //开启输入捕捉噪声抑制器,输入捕捉下降沿触发,无时钟
        TIMSK |= (1 << TICIE1) | (1 << TOIE1); //定时计数器1输入捕捉使能,溢出中断使能
        sei(); //开启总中断
}

int main(void)
{
        led_init();
        seg_init();
        portd_init();
        timer1_init();
    while(1)
    {
                PER = ((65535*count+PER)*8); //计算两次按键时间间隔
                TempData[0] = DuanMa[PER/10000000];
                TempData[1] = DuanMa[(PER%10000000)/1000000];
                TempData[2] = DuanMa[(PER%10000000%1000000)/100000];
                TempData[3] = DuanMa[(PER%10000000%1000000%100000)/10000];
                TempData[4] = DuanMa[(PER%10000000%1000000%100000%10000)/1000];
                TempData[5] = DuanMa[(PER%10000000%1000000%100000%10000%1000)/100];
                TempData[6] = DuanMa[(PER%10000000%1000000%100000%10000%1000%100)/10];
                TempData[7] = DuanMa[(PER%10000000%1000000%100000%10000%1000%100)%10];
                seg_display(0,8);
    }
}

ISR(TIMER1_CAPT_vect)
{
        num++;
        if(((num % 2) == 1) && ((TIFR & 0x04) == 0x00))
                {
                        PER = 0; //初始为0
                        count = 0; //溢出次数为0
                        TCNT1 = 0; //计数器初值为0
                        ICR1 = 0; //捕捉寄存器初值为0
                        PER1 = ICR1; //标记初值
                        TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); //开启8分频
                }
        if(((num % 2) == 0) && ((TIFR & 0x04) == 0x00))
                {
                        TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); //时钟停止
                        PER2 = ICR1; //读取第二次按键后计数器值
                        PER = PER2 - PER1; //计算两次按下时间间隔
                }
}

ISR(TIMER2_OVF_vect)
{
        count++; //溢出次数计数
}

相关帖子

沙发
wangch_sh| | 2014-8-27 15:00 | 只看该作者
确保中断正常进入

使用特权

评论回复
板凳
SD10A| | 2014-8-31 22:07 | 只看该作者
TCCR1B |= (1 << ICNC1) | (0 << ICES1) | (0 << CS12) | (0 << CS11) | (0 << CS10);
这句 设成了无时钟了 TC停止,使用不了普通模式了 见TABLE48
再说我认为你这个写法有问题  TCCR1B各位默认为0  你只要或上取1的位  其他可以不写
欢迎指教

使用特权

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

本版积分规则

10

主题

35

帖子

1

粉丝