搜索
bottom↓
回复: 8

马老师,您的AVR-51学习板3*4键盘设计有小问题

[复制链接]

出0入0汤圆

发表于 2007-3-22 13:53:23 | 显示全部楼层 |阅读模式
那行线上的三个电阻阻值太大了,发出的低电平根本读不回来。不该用5K的电阻。我搞了很久才明白我的扫描程序为什么扫不到,原来都是电阻惹的祸!希望改进一下。

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2007-3-23 00:08:13 | 显示全部楼层
这快板使用了多年了,我读键盘没有发生过读不到低电平的现象。



如果你使用中发现读不到,请检查



1。读键盘的I/O口线是否定义成输入状态,且内部上拉有效。AVR的内部上拉电阻>50K。当行线输出为“0”时,按键按下后电平值小于 5/(55)* 5 = 0.45v,应该是低电平,绝对不是高电平,对CMOS器件,高电平为Vcc*0.7 = 5*0.7 = 3.5v。



2。行线输出“0”后,需要等待一个时钟周期后读列线。这样才能读到正确的值。



====================================================================



实际上3个串连电阻可以省掉的。但怕有的人设置错误,将列线设置为输出状态,而又输出“1”,这样有可能造成MCU I/O脚的损坏。(列线的“1”通过按键与行线的“0”断路!!)。多功能实验板是为新手设计的,加上电阻防止万一。

出0入0汤圆

 楼主| 发表于 2007-3-23 09:01:15 | 显示全部楼层
哦,可是我完全按您的读键盘程序,不更改电阻就读不到按键。换成300欧的电阻才行。程序如下,基本是抄您教材上的程序。是什么原因呢?我想了很久都想不明白。烦请老师指点。



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

This program was produced by the

CodeWizardAVR V1.24.8c Professional

Automatic Program Generator

© Copyright 1998-2006 Pavel Haiduc, HP InfoTech s.r.l.

http://www.hpinfotech.com



Project :

Version :

Date    : 2007-3-19

Author  : F4CG                           

Company : F4CG                           

Comments:





Chip type           : ATmega16L

Program type        : Application

Clock frequency     : 11.059200 MHz

Memory model        : Small

External SRAM size  : 0

Data Stack size     : 256

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



#include <mega16.h>

flash char led_7[13]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,

                      0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x40};

flash char position[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};

char dis_buff[8];

char key_stime_counter;

char posit;

bit key_stime_ok;

void display(void)

{

    PORTB=0xff;

    PORTA=led_7[dis_buff[posit]];

    PORTB=position[posit];

    if(++posit>=8)posit=0;

}



// Timer 0 output compare interrupt service routine

interrupt [TIM0_COMP] void timer0_comp_isr(void)

{

// Place your code here

    display();

    if(++key_stime_counter>=10)

    {

        key_stime_counter=0;

        key_stime_ok=1;

    }

}



#define no_key  255

#define k1_1    1

#define k1_2    2

#define k1_3    3

//#define k1_4    4

#define k2_1    4

#define k2_2    5

#define k2_3    6

//#define k2_4    4

#define k3_1    7

#define k3_2    8

#define k3_3    9

//#define k1_4    4

#define k4_1    10

#define k4_2    0

#define k4_3    11

//#define k4_4    4

#define key_mask 0b00000111



char key_state,key_value,key_line;

char read_keyboard(void)

{

   

   char key_return=no_key,i;

   switch(key_state)

   {

       case 0:              

           key_line=0b00001000;

           for(i=1;i<4;i++)  

           {

               PORTD=~key_line;  //0b11110111

               PORTD=~key_line;//

               key_value=key_mask&PIND;

               if(key_value==key_mask)//

                   key_line<<=1;

               else                     //

               {

                   key_state++;

                   break;              

               }

           }

           break;                  

       case 1:                     //

           

           PORTD=~key_line;  //0b11110111

           PORTD=~key_line;//

           if(key_value==(key_mask&PIND))//

           {

               

                switch(key_line|key_value)

                {

                 //&micro;&Uacute;&Ograve;&raquo;&ETH;&ETH;

                    case 0b00001110:

                         key_return=k1_1;

                         break;

                    case 0b00001101:

                         key_return=k1_2;

                         break;

                    case 0b00001011:

                         key_return=k1_3;

                         break;

                 //&micro;&Uacute;&para;&thorn;&ETH;&ETH;        

                    case 0b00010110:

                         key_return=k2_1;

                         break;

                    case 0b00010101:

                         key_return=k2_2;

                         break;

                    case 0b00010011:

                         key_return=k2_3;

                         break;

                   //&micro;&Uacute;&Egrave;&yacute;&ETH;&ETH;      

                    case 0b00100110:

                         key_return=k3_1;

                         break;

                    case 0b00100101:

                         key_return=k3_2;

                         break;

                    case 0b00100011:

                         key_return=k3_3;

                         break;

                    //&micro;&Uacute;&Euml;&Auml;&ETH;&ETH;

                    case 0b01000110:

                         key_return=k4_1;

                         break;

                    case 0b01000101:

                         key_return=k4_2;

                         break;

                    case 0b01000011:

                         key_return=k4_3;

                         break;

                 }

                 key_state++;

           }

           else

                 key_state--;     //

           break;

       case 2:

           PORTD=0b00000111;

           PORTD=0b00000111;

           if((key_mask&PIND)==key_mask)//

               key_state=0;

           break;

   }      

           

   return key_return;

}

//*/

//用这个读也是读不到任何按键。

/*char read_keyboard(void)

{

     PORTD=0;

     PORTD=0;

     if(PIND.0==0)

        return 3;

     else

        return 0;

}

*/

// Declare your global variables here



void main(void)

{  

  char i,key_temp;

// Declare your local variables here



// Input/Output Ports initialization

// Port A initialization

// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out

// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0

PORTA=0x00;

DDRA=0xFF;



// Port B initialization

// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out

// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0

PORTB=0xff;

DDRB=0xFF;



// Port C initialization

// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=In Func1=In Func0=In

// State7=0 State6=0 State5=0 State4=0 State3=0 State2=P State1=P State0=P

PORTC=0xF7;

DDRC=0xF8;



// Port D initialization

// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=In Func1=In Func0=In

// State7=1 State6=1 State5=1 State4=1 State3=1 State2=P State1=P State0=P

PORTD=0B11111111;

DDRD=0B11111000;//0xF8;



// Timer/Counter 0 initialization

// Clock source: System Clock

// Clock value: 172.800 kHz

// Mode: CTC top=OCR0

// OC0 output: Disconnected

TCCR0=0x0B;

TCNT0=0xAD;

OCR0=0xAD;



// Timer/Counter 1 initialization

// Clock source: System Clock

// Clock value: Timer 1 Stopped

// Mode: Normal top=FFFFh

// OC1A output: Discon.

// OC1B output: Discon.

// Noise Canceler: Off

// Input Capture on Falling Edge

// Timer 1 Overflow Interrupt: Off

// Input Capture Interrupt: Off

// Compare A Match Interrupt: Off

// Compare B Match Interrupt: Off

TCCR1A=0x00;

TCCR1B=0x00;

TCNT1H=0x00;

TCNT1L=0x00;

ICR1H=0x00;

ICR1L=0x00;

OCR1AH=0x00;

OCR1AL=0x00;

OCR1BH=0x00;

OCR1BL=0x00;



// Timer/Counter 2 initialization

// Clock source: System Clock

// Clock value: Timer 2 Stopped

// Mode: Normal top=FFh

// OC2 output: Disconnected

ASSR=0x00;

TCCR2=0x00;

TCNT2=0x00;

OCR2=0x00;



// External Interrupt(s) initialization

// INT0: Off

// INT1: Off

// INT2: Off

MCUCR=0x00;

MCUCSR=0x00;



// Timer(s)/Counter(s) Interrupt(s) initialization

TIMSK=0x02;



// Analog Comparator initialization

// Analog Comparator: Off

// Analog Comparator Input Capture by Timer/Counter 1: Off

ACSR=0x80;

SFIOR=0x00;

for(i=0;i<8;i++)

{

    dis_buff=12;

}



// Global enable interrupts

#asm("sei")



while (1)

      {

      // Place your code here

       if(key_stime_ok)

       {

           key_stime_ok=0;

           key_temp=read_keyboard();  

           if(key_temp != 0xff)

           {

                for(i=0;i<8;i++)

                {

                    //dis_buff=dis_buff[i+1];

                    dis_buff=key_temp;

                }

           }

       }

      };

}

出0入0汤圆

发表于 2007-3-23 10:19:58 | 显示全部楼层
PORTD=0;

     PORTD=0;

     if(PIND.0==0)

        return 3;

     else

        return 0;

===============================

PORTD = 0  !!已经把上拉去掉了!!

出0入0汤圆

 楼主| 发表于 2007-3-24 10:09:51 | 显示全部楼层
马老师,不是说先设置为上拉PORTD=0B11111111; 再设置为输入,DDRD=0B11111000; 之后更改PORTD寄存器的值就不会改变上拉了吗?(即设置为输入口后,PORTD寄存器已经控制不到上拉电阻了。)

我的程序改为:

    PORTD&=0B00000111;  

     PORTD=0B00000111;  

     if(PIND.0==0)  

        return 3;  

     else  

        return 0;  





一样的结果。怪了,原理上如您所诉,我也看懂了,5K应该没有任何问题的呀,您的板子是完全正确的。但我的必须把5k电阻换掉才行。我自己慢慢琢磨吧,实在不好意思浪费您宝贵的时间了。谢谢您不厌其烦的指点。
-----此内容被yarak_ma于2007-03-24,10:12:34编辑过

出0入0汤圆

发表于 2007-3-24 12:13:19 | 显示全部楼层
我将第9章的例子简易手机键盘的程序又试了一次,肯定可以的,我的板上也是串了3个5.1k电阻,电路图与9章图一样,不同的是3个上拉电阻没用,使用内部上拉。



程序如下:

#include <mega16.h>

flash char led_7[13]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,        // 字型码

0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x40};

                                                                          // 后3位为 "A","b","-"       

flash char position[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};



char        dis_buff[8];                                // 显示缓冲区,存放要显示的8个字符的段码值

char        key_stime_counter;

char        posit;

bit        key_stime_ok;



void display(void)                                        // 8位LED数码管动态扫描函数

{

                PORTC = 0xff;

                PORTA = led_7[dis_buff[posit]];

                PORTC = position[posit];

                if (++posit >=8 ) posit = 0;

}



// Timer 0 比较匹配中断服务,2ms定时

interrupt [TIM0_COMP] void timer0_comp_isr(void)

{

                display();                                                // 调用LED扫描显示

                if (++key_stime_counter >=5)

                {

                        key_stime_counter = 0;

                        key_stime_ok = 1;                                // 10ms到

                }       

}

#define No_key         255

#define K1_1        1

#define K1_2        2

#define K1_3        3

#define K2_1        4

#define K2_2        5

#define K2_3        6

#define K3_1        7

#define K3_2        8

#define K3_3        9

#define K4_1        10

#define K4_2        0

#define K4_3        11

#define Key_mask        0b00000111





char read_keyboard()

{       

static char key_state = 0, key_value, key_line;

char key_return = No_key,i;

        switch (key_state)

        {

                case 0:

                        key_line = 0b00001000;

                        for (i=1; i<=4; i++)                                        // 扫描键盘

                        {       

                                PORTD = ~key_line;                                        // 输出行线电平

                                PORTD = ~key_line;                                        // 必须送2次!!!

                             key_value = Key_mask & PIND;                // 读列电平

                                if (key_value == Key_mask)

                                        key_line <<= 1;                                // 没有按键,继续扫描

                                else

                                {

                                        key_state++;                                        // 有按键,停止扫描

                                        break;                                                // 转消抖确认状态

                                }

                        }

                        break;

                case 1:

                        if (key_value == (Key_mask & PIND))                // 再次读列电平,

                        {

                                switch (key_line | key_value)                // 与状态0的相同,确认按键

                                {                                                                // 键盘编码,返回编码值

                                        case 0b00001110:

                                                key_return = K1_1;

                                                break;

                                        case 0b00001101:

                                                key_return = K1_2;

                                                break;

                                        case 0b00001011:

                                                key_return = K1_3;

                                                break;

                                        case 0b00010110:

                                                key_return = K2_1;

                                                break;

                                        case 0b00010101:

                                                key_return = K2_2;

                                                break;

                                        case 0b00010011:

                                                key_return = K2_3;

                                                break;

                                        case 0b00100110:

                                                key_return = K3_1;

                                                break;

                                        case 0b00100101:

                                                key_return = K3_2;

                                                break;

                                        case 0b00100011:

                                                key_return = K3_3;

                                                break;

                                        case 0b01000110:

                                                key_return = K4_1;

                                                break;

                                        case 0b01000101:

                                                key_return = K4_2;

                                                break;

                                        case 0b01000011:

                                                key_return = K4_3;

                                                break;

                                }

                                key_state++;                                // 转入等待按键释放状态

                        }

                        else

                                key_state--;                                // 两次列电平不同返回状态0,(消抖处理)

                        break;                                               

                case 2:                                                        // 等待按键释放状态

                        PORTD = 0b00000111;                        // 行线全部输出低电平

                        PORTD = 0b00000111;                        // 重复送一次

                        if ( (Key_mask & PIND) == Key_mask)

                                key_state=0;                                // 列线全部为高电平返回状态0

                        break;

        }

        return key_return;

}



void main(void)

{

                char i, key_temp;

       

                PORTA = 0x00;                                                        // 显示控制I/O端口初始化

                DDRA = 0xFF;

                PORTC = 0xFF;

                DDRC = 0xFF;

                PORTD = 0xFF;                                                        // 键盘接口初始化

                DDRD = 0xF8;                                                        // PD2、PD1、PD0列线,输入方式,上拉有效

                // T/C0 初始化

                TCCR0=0x0B;                        // 内部时钟,64分频(4M/64=62.5KHz),CTC模式

                TCNT0=0x00;

                OCR0=0x7C;                        // OCR0 = 0x7C(124),(124+1)/62.5=2ms

                TIMSK=0x02;                        // 允许T/C0比较匹配中断



                for (i=0; i<8 ;i++)

                {dis_buff= 12;}                // LED初始显示8个"-"

                #asm("sei")                        // 开放全局中断



                while (1)

                {

                        if (key_stime_ok)                               

                        {

                                key_stime_ok = 0;                                // 10ms到

                                key_temp = read_keyboard();                // 调用键盘接口函数读键盘

                                if (key_temp != No_key)

                                {                                                        // 有按键按下

                                        for (i=0; i<7; i++)

                                        {dis_buff = dis_buff[i+1];}        // LED显示左移一位

                                        dis_buff[7] = key_temp;                 // 最右显示新按下键的键值

                                }

                        }

                };

}

出0入0汤圆

发表于 2007-3-24 12:28:08 | 显示全部楼层
如果不是程序的问题,那么还有一个可能是否你的系统时钟频率非常高,使得(由于5k电阻的充放电时间)你读I/O时电平没有稳定。解决的办法是,送键扫描语句执行3次。





不过,我在AVR-51板上已经试了11.0592M,原来的程序没有问题,键盘读的非常好。

出0入0汤圆

 楼主| 发表于 2007-3-24 12:46:51 | 显示全部楼层
谢谢马老师!马老师真的是师之模范。我一个小问题纠缠这么久了你都不烦。呵呵!我键扫描语句执行了四次,就可以了。最后基本确定了原因:

    我的板子上同时用了led数码管,蜂鸣器,8*8点阵led,晶体用了11.0592M,而我的电源只能输出400mA,可能是驱动力不够了。换了1000mA电源也可以解决问题。看来我的硬件水平太低了。需要好好提高。

出0入0汤圆

发表于 2011-7-12 11:14:08 | 显示全部楼层
学习了
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 02:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表