搜索
bottom↓
回复: 20

发个M16的学习程序,8个ADC输入通道采集电压值,数码管显示

[复制链接]

出0入0汤圆

发表于 2010-12-24 22:36:41 | 显示全部楼层 |阅读模式
话不多说,程序如下:
/*系统时钟采用内部8M时钟,编译环境为GCC*/
#include <avr/io.h>
#include <avr/interrupt.h>

#define uchar unsigned char
#define uint unsigned int
#define SegAddrPort PORTD  //数码管位选接口
#define SegDataPort PORTC   //数码管端选接口
#define GPInterruptON() (SREG |= (1 << 7))
#define GPInterruptOFF() (SREG &= ~(1 << 7))
#define ADCON() (ADCSRA |= (1 << ADEN))
#define ADCOFF() (ADCSRA &= ~(1 << ADEN))

const uchar SegTab[] = {0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
enum Row
{Row0 = 0,Row1,Row2,Row3,Row4,Row5,Row6,Row7};  //定义8个输入通道
enum Row CurrentRow,NextRow;
uchar ShowRow;
uchar ScanCnt;
uint ADCData[8];

void GPIOInit(void);
void Timer0Init(void);
void INT0Init(void);
void ADCInit(void);
void DisplayData(void);
void SystemRun(void);
int main(void)
{
        GPIOInit();
        Timer0Init();
        INT0Init();
        ADCInit();
        GPInterruptON();
        while(1)
        {
                SystemRun();               
        }
}

void GPIOInit(void)   //IO口初始化函数
{
        DDRA = 0X00;
        PORTA = 0X00;
        DDRB = 0XFF;
        PORTB = 0X00;
        DDRC = 0XFF;
        PORTC = 0X00;
        DDRD |= 0XF0;
        PORTD &= 0X0F;
}

void Timer0Init(void)  //定时器0初始化函数
{
        OCR0 = 0XF9;       //比较TOP值
        TIMSK |= 0X02;     //开中断
        TCCR0 = 0X0B;      //CTC模式,64分频
}

void INT0Init(void)    //外部中断0初始化函数,下降沿触发
{
        MCUCR |= 0X02;       //下降沿触发
        GICR |= 0X40;        //开中断
}

void ADCInit(void)     //ADC初始化函数
{                     
        ADMUX  = 0X40;     //参考电压为AVCC=5V,转换结果默认右对齐
        ADCSRA = 0XEE;     //ADC时钟源为8M/64=125K
        SFIOR = 0X60;      //ADC的转换触发源选择定时器0比较匹配
}

void DisplayData(void)  //数码管显示函数
{
        uint ADCDataTemp;
        ADCDataTemp = ADCData[ShowRow];
        if((ADCDataTemp % 10) >= 5)          //转换结果4舍5入,精度为0.01
                ADCDataTemp = ADCDataTemp / 10 +1;
        else
                ADCDataTemp = ADCDataTemp / 10;
        switch(ScanCnt)
        {
                case 0: SegAddrPort = (1 << 4);
                                SegDataPort = SegTab[ShowRow];     //显示通道号,为0--7
                                break;                               
                case 1: SegAddrPort = (1 << 5);
                                SegDataPort = SegTab[ADCDataTemp / 100] & 0X7F;  //显示个位及小数点
                                break;                               
                case 2: SegAddrPort = (1 << 6);
                                SegDataPort = SegTab[(ADCDataTemp % 100) / 10];   //显示十分位
                                break;                               
                case 3: SegAddrPort = (1 << 7);
                                SegDataPort = SegTab[ADCDataTemp % 10];    //显示百分位
                                break;                               
        }       
}

void SystemRun(void)
{
        switch(CurrentRow)
        {
                case Row0:  NextRow = Row1;
                                        break;
                case Row1:  NextRow = Row2;
                                        break;
                case Row2:  NextRow = Row3;
                                        break;
                case Row3:  NextRow = Row4;
                                        break;
                case Row4:  NextRow = Row5;
                                        break;
                case Row5:  NextRow = Row6;
                                        break;
                case Row6:  NextRow = Row7;
                                        break;
                case Row7:  NextRow = Row0;
                                        break;
        }
        DisplayData();
}

ISR(TIMER0_COMP_vect)     //定时器0,2ms比较匹配中断函数,产生数码管的扫描信号
{
        if(ScanCnt >= 3)
                ScanCnt = 0;
        else
                ScanCnt ++;
}

ISR(INT0_vect)    //外部中断0函数,切换显示值
{
        if(ShowRow >= 7)
                ShowRow        = 0;
        else
                ShowRow ++;
}

ISR(ADC_vect)    //ADC转换完成中断函数,读取转换值,更新输入通道
{
        ADCOFF();
        ADCData[CurrentRow] = ADC * 4.883;       
        ADMUX = ((ADMUX & 0XE0) | NextRow);
        CurrentRow = NextRow;
        ADCON();               
}


仿真图 (原文件名:ADC.jpg)

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

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2010-12-24 22:39:34 | 显示全部楼层
自己顶一下……

出0入0汤圆

发表于 2010-12-26 12:49:16 | 显示全部楼层
很不错!支持!

出0入0汤圆

发表于 2010-12-26 20:05:01 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-26 20:07:11 | 显示全部楼层
假期要学的 mark

出0入0汤圆

发表于 2010-12-27 12:59:14 | 显示全部楼层
标记

出0入0汤圆

发表于 2010-12-27 20:06:21 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-12-27 20:33:59 | 显示全部楼层
谢谢分享 mark

出0入0汤圆

发表于 2011-3-4 15:26:15 | 显示全部楼层
GPInterruptON(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~

出0入0汤圆

 楼主| 发表于 2011-3-22 15:36:09 | 显示全部楼层
回复【8楼】feizhoubaoyu
gpinterrupton(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~
-----------------------------------------------------------------------

这个是个宏定义,开全局中断,程序是完整的。

出0入0汤圆

发表于 2011-5-9 12:37:30 | 显示全部楼层
学习了!

出0入0汤圆

发表于 2011-5-9 15:38:50 | 显示全部楼层
这个要MARK一下

出0入0汤圆

发表于 2011-10-9 17:04:54 | 显示全部楼层
马克

出0入0汤圆

发表于 2012-2-17 16:08:28 | 显示全部楼层
回复【楼主位】hwg_LDW
-----------------------------------------------------------------------

case 1: SegAddrPort = (1 << 5);
SegDataPort = SegTab[ADCDataTemp / 100] & 0X7F;  //显示个位及小数点
break;
这一句是怎么显示个位和小数点的啊?比如AD转换结果是310,310/100=3,SegTab[3]=0xb0吧,再与0x7f相与,结果是3,也就是显示3,请问这个小数点是怎么显示的?

出0入0汤圆

发表于 2012-2-17 23:02:03 | 显示全部楼层
see

出0入0汤圆

发表于 2012-3-24 18:09:41 | 显示全部楼层
收下  :)

出0入0汤圆

发表于 2012-3-24 23:57:05 | 显示全部楼层
不错,支持一下

出0入0汤圆

发表于 2012-3-25 00:33:36 | 显示全部楼层
好东西,看来M16还是比M8 AD功能强很多

出0入0汤圆

发表于 2012-3-27 19:50:33 | 显示全部楼层
很好很强大 正需要学习呢

出0入0汤圆

发表于 2012-4-9 15:43:20 | 显示全部楼层
Mark,支持一下

出0入0汤圆

发表于 2014-4-26 09:55:19 | 显示全部楼层
谢谢楼主分享心得,我有一个问题想请教一下:
enum Row
{Row0 = 0,Row1,Row2,Row3,Row4,Row5,Row6,Row7};  //定义8个输入通道  
八路的时候是正常的,但是如果我改成3路,就不能正常运行,是什么原因呢?求解惑!参照楼主的程序改的部分如下:
enum Row
{Row0 = 0,Row1,Row2}; //改成3路输入

switch(CurrentRow)   //改成3路输入切换
        {
                case Row0:  NextRow = Row1;
                                        break;
                case Row1:  NextRow = Row2;
                                        break;
                case Row2:  NextRow = 0;
                                        break;                             
        }

难道哪里出错了,程序调了好久多运行不了?为什么呢?难道哪里要跟着修改,求指教,谢谢~
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-7-23 22:37

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

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