hwg_LDW 发表于 2010-12-24 22:36:41

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

话不多说,程序如下:
/*系统时钟采用内部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;

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;
        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;   //显示通道号,为0--7
                                break;                               
                case 1: SegAddrPort = (1 << 5);
                                SegDataPort = SegTab & 0X7F;//显示个位及小数点
                                break;                               
                case 2: SegAddrPort = (1 << 6);
                                SegDataPort = SegTab[(ADCDataTemp % 100) / 10];   //显示十分位
                                break;                               
                case 3: SegAddrPort = (1 << 7);
                                SegDataPort = SegTab;    //显示百分位
                                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 = ADC * 4.883;       
        ADMUX = ((ADMUX & 0XE0) | NextRow);
        CurrentRow = NextRow;
        ADCON();               
}

http://cache.amobbs.com/bbs_upload782111/files_35/ourdev_606958G5PE0B.jpg
仿真图 (原文件名:ADC.jpg)

hwg_LDW 发表于 2010-12-24 22:39:34

自己顶一下……

majielimid 发表于 2010-12-26 12:49:16

很不错!支持!

cuikai12345 发表于 2010-12-26 20:05:01

mark

rockethuojian 发表于 2010-12-26 20:07:11

假期要学的 mark

czhongli 发表于 2010-12-27 12:59:14

标记

wanglong 发表于 2010-12-27 20:06:21

MARK

poet_lee 发表于 2010-12-27 20:33:59

谢谢分享 mark

feizhoubaoyu 发表于 2011-3-4 15:26:15

GPInterruptON(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~

hwg_LDW 发表于 2011-3-22 15:36:09

回复【8楼】feizhoubaoyu
gpinterrupton(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~
-----------------------------------------------------------------------

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

hendeli909 发表于 2011-5-9 12:37:30

学习了!

ss5566 发表于 2011-5-9 15:38:50

这个要MARK一下

zzzzzzzzz2 发表于 2011-10-9 17:04:54

马克

mianchaodahai 发表于 2012-2-17 16:08:28

回复【楼主位】hwg_LDW
-----------------------------------------------------------------------

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

rongDDR 发表于 2012-2-17 23:02:03

see

lixupeng 发表于 2012-3-24 18:09:41

收下:)

Bicycle 发表于 2012-3-24 23:57:05

不错,支持一下

chary_5 发表于 2012-3-25 00:33:36

好东西,看来M16还是比M8 AD功能强很多

囧囧有神经 发表于 2012-3-27 19:50:33

很好很强大 正需要学习呢

narcissus8912 发表于 2012-4-9 15:43:20

Mark,支持一下

kamfun 发表于 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;                           
      }

难道哪里出错了,程序调了好久多运行不了?为什么呢?难道哪里要跟着修改,求指教,谢谢~
页: [1]
查看完整版本: 发个M16的学习程序,8个ADC输入通道采集电压值,数码管显示