发个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) 自己顶一下…… 很不错!支持! mark 假期要学的 mark 标记 MARK 谢谢分享 mark GPInterruptON(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~ 回复【8楼】feizhoubaoyu
gpinterrupton(); 这个是干嘛的,后面没有这个子程序啊。是不是你忘记粘贴上来了~
-----------------------------------------------------------------------
这个是个宏定义,开全局中断,程序是完整的。 学习了! 这个要MARK一下 马克 回复【楼主位】hwg_LDW
-----------------------------------------------------------------------
case 1: SegAddrPort = (1 << 5);
SegDataPort = SegTab & 0X7F;//显示个位及小数点
break;
这一句是怎么显示个位和小数点的啊?比如AD转换结果是310,310/100=3,SegTab=0xb0吧,再与0x7f相与,结果是3,也就是显示3,请问这个小数点是怎么显示的? see 收下:) 不错,支持一下 好东西,看来M16还是比M8 AD功能强很多 很好很强大 正需要学习呢 Mark,支持一下 谢谢楼主分享心得,我有一个问题想请教一下:
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]