资源描述
AVR AD采集转换程序,带数字滤波
1. //本例使用内部参考电压,ADc0输入,采集的信号通过LED显示。
2.
3. //ICC-AVR application builder : 2006-9-3 11:42:36
4. // Target : M32
5. // Crystal: 7.3728Mhz
6. // 2.56v 片内基准电压,输入a1:即adc0
7. // 误差为: 连续测量模式。
8. // 精度8,输出左对齐 ADLAR=1
9. // 注意:参考电压一定要高于被测电压。
10. #include <iom32v.h>
11. #include <macros.h>
12. //数字滤波
13. #define a 0xF4
14. // a=0.95
15. #define b 0x0D
16. // b=1-a=0.05
17. const led_table[16]={0xa0,0xfc,0xc1,0xd0,0x9c,0x92,0x82,0xf8,0x80,0x90,0x88,0x86,0xc7,0xc4,0x83,0x8b};// 0~~f
18. typedef unsigned char uint8;
19. uint8 value,value1=0;
20. int x; //最终的值 10位
21. volatile uint8 i,j=0;
22.
23. //delay
24. /***********************************/
25. void Delay100us(uint8 n)
26. {
27. uint8 i;
28. for(i=36;n!=0;n--)
29. while(--i);
30. }
31.
32. void Delay1s(uint8 n)
33. {
34. n=n*10;
35. for (;n!=0;n--){
36. Delay100us(200);
37. }
38. }
39. /******************************/
40.
41. void port_init(void)
42. {
43. PORTA = 0x00; //做adc输入时不可上拉。
44. DDRA = 0x00;
45. PORTB = 0xFF;
46. DDRB = 0xFF;
47. PORTC = 0xFF;
48. DDRC = 0x00;
49. PORTD = 0xFF;
50. DDRD = 0x00;
51. }
52.
53. //ADC initialize
54. // Conversion time: 225uS
55. void adc_init(void)
56. {
57. ADCSR = 0x00; //disable adc
58. ADMUX = 0xC0|(1<<ADLAR); // 2.56v 片内基准电压 /select adc input 0 /
59. ACSR = 0x80; // 使能adc可用,不用修改
60. ADCSRA = 0xA8; // ADC使能,自动触发模式使能,触发源由SFIOR确定,中断使能,分频因子为2
61. SFIOR = 0X60; // 触发源设置为:定时器比较匹配
62. }
63.
64. //TIMER0 initialize - prescale:1024
65. // WGM: Normal
66. // desired value: 1Hz
67. // actual value: 35.556mSec (-3455.6%)
68. void timer0_init(void)
69. {
70. TCCR0 = 0x00; //stop
71. TCNT0 = 0x01; //set count
72. OCR0 = 0x02; //set compare //FF
73. TCCR0 = 0x0D; //start timer 1024分频 CTC比较输出 定时时间:256/(7.3728Mhz/1024)=35.556ms
74. }
75.
76. #pragma interrupt_handler timer0_ovf_isr:10
77. void timer0_ovf_isr(void)
78. {
79. TCNT0 = 0x01; //reload counter value
80. j++;
81. if(j==0) CLI();
82. }
83.
84. #pragma interrupt_handler timer0_comp_isr:20
85. void timer0_comp_isr(void)
86. {
87. //compare occured TCNT0=OCR0
88. TCNT0 = 0x01; //reload counter value
89. i++;
90. if(i==0) CLI();
91. }
92.
93. #pragma interrupt_handler adc_isr:15
94. void adc_isr(void)
95. {
96. //conversion complete, read value (int) using...
97. //ADIF 硬件清零
98. ADCSRA |= (1<<ADIF);//ADIF置1清位
99. value=ADCH; //Read 8 low bits first (important)
100. // value|=(int)ADCH << 8; //read 2 high bits and shift into top byt
101. //value=(value*2.56)/1024;
102. //数字滤波
103. value1=(char)(((int)a*value1 + (int)b*value)>>8);
104. //value1=(int)(a*value1+b*value);
105. x = 0|value1;
106. x= x <<2; //真实的10位值
107. if(((x/100)<16)&&((x/100)>0))
108. PORTB = led_table[x/100];
109. else PORTB = led_table[0];
110. /*/测试
111. j++;
112. if(j==255)
113. {
114. //TIMSK = 0x00;
115. ADCSRA&=~(1<<ADIE);
116. CLI();
117. PORTB = led_table[0];
118. }
119. */
120. }
121.
122. //call this routine to initialize all peripherals
123. void init_devices(void)
124. {
125. //stop errant interrupts until set up
126. CLI(); //disable all interrupts
127. port_init();
128. timer0_init();
129. adc_init();
130.
131. MCUCR = 0x00; //电源管理项
132. GICR = 0x00; //boot 选项
133. TIMSK = 0x03; //timer interrupt sources 比较输出
134. SEI(); //re-enable interrupts
135. //all peripherals are now initialized
136. }
137.
138. void main(void)
139. {
140. init_devices();
141.
142. ADCSRA|=(1<<ADSC); //连续模式,开始AD转换
143. while(1)
144. {
145.
146. PORTB = led_table[0];
147.
148. // while ((ADCSR&(1<<ADIF))==0); //等待ADC完成,实际程序中可以运行其它任务
149.
150. // ADCSRA&=~(1<<ADIE); //禁止ADC中断
151.
152. // Delay1s(1);
153. }
154. }
单片机入门系列—avr AD转换程序
//本例使用内部参考电压,ADc0输入,采集的信号通过LED显示。
//整理: AVR与虚拟仪器 古欣
//ICC-AVR application builder : 2006-9-3 11:42:36
// Target : M32
// Crystal: 7.3728Mhz
// 2.56v 片内基准电压,输入a1:即adc0
// 误差为: 连续测量模式。
// 精度8,输出左对齐 ADLAR=1
// 注意:参考电压一定要高于被测电压。
#include <iom32v.h>
#include <macros.h>
//数字滤波
#define a 0xF4
// a=0.95
#define b 0x0D
// b=1-a=0.05
const led_table[16]={0xa0,0xfc,0xc1,0xd0,0x9c,0x92,0x82,0xf8,0x80,0x90,0x88,0x86,0xc7,0xc4,0x83,0x8b};// 0~~f
typedef unsigned char uint8;
uint8 value,value1=0;
int x; //最终的值 10位
volatile uint8 i,j=0;
//delay
/***********************************/
void Delay100us(uint8 n)
{
uint8 i;
for(i=36;n!=0;n--)
while(--i);
}
void Delay1s(uint8 n)
{
n=n*10;
for (;n!=0;n--){
Delay100us(200);
}
}
/******************************/
void port_init(void)
{
PORTA = 0x00; //做adc输入时不可上拉。
DDRA = 0x00;
PORTB = 0xFF;
DDRB = 0xFF;
PORTC = 0xFF;
DDRC = 0x00;
PORTD = 0xFF;
DDRD = 0x00;
}
//ADC initialize
// Conversion time: 225uS
void adc_init(void)
{
ADCSR = 0x00; //disable adc
ADMUX = 0xC0|(1<<ADLAR); // 2.56v 片内基准电压 /select adc input 0 /
ACSR = 0x80; // 使能adc可用,不用修改
ADCSRA = 0xA8; // ADC使能,自动触发模式使能,触发源由SFIOR确定,中断使能,分频因子为2
SFIOR = 0X60; // 触发源设置为:定时器比较匹配
}
//TIMER0 initialize - prescale:1024
// WGM: Normal
// desired value: 1Hz
// actual value: 35.556mSec (-3455.6%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x01; //set count
OCR0 = 0x02; //set compare //FF
TCCR0 = 0x0D; //start timer 1024分频 CTC比较输出 定时时间:256/(7.3728Mhz/1024)=35.556ms
}
#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0 = 0x01; //reload counter value
j++;
if(j==0) CLI();
}
#pragma interrupt_handler timer0_comp_isr:20
void timer0_comp_isr(void)
{
//compare occured TCNT0=OCR0
TCNT0 = 0x01; //reload counter value
i++;
if(i==0) CLI();
}
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
//conversion complete, read value (int) using...
//ADIF 硬件清零
ADCSRA |= (1<<ADIF);//ADIF置1清位
value=ADCH; //Read 8 low bits first (important)
// value|=(int)ADCH << 8; //read 2 high bits and shift into top byt
//value=(value*2.56)/1024;
//数字滤波
value1=(char)(((int)a*value1 + (int)b*value)>>8);
//value1=(int)(a*value1+b*value);
x = 0|value1;
x= x <<2; //真实的10位值
if(((x/100)<16)&&((x/100)>0))
PORTB = led_table[x/100];
else PORTB = led_table[0];
/*/测试
j++;
if(j==255)
{
//TIMSK = 0x00;
ADCSRA&=~(1<<ADIE);
CLI();
PORTB = led_table[0];
}
*/
}
//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer0_init();
adc_init();
MCUCR = 0x00; //电源管理项
GICR = 0x00; //boot 选项
TIMSK = 0x03; //timer interrupt sources 比较输出
SEI(); //re-enable interrupts
//all peripherals are now initialized
}
void main(void)
{
init_devices();
ADCSRA|=(1<<ADSC); //连续模式,开始AD转换
while(1)
{
PORTB = led_table[0];
// while ((ADCSR&(1<<ADIF))==0); //等待ADC完成,实际程序中可以运行其它任务
// ADCSRA&=~(1<<ADIE); //禁止ADC中断
// Delay1s(1);
}
}
这两天在看别人写的AVR中AD转换程序,自已拼凑起一个能用的,觉得蛮好玩。贴出来共享
下面这个程序在ATMEGA16L上通过,直接在LCM上显示PA0口的电压。单位是0.1mV
本程序只是偶试验AVR的AD转换功能而写,也并非我原创,只是消化了别人的程序凑起来的。但绝对能用。
同时也望大虾们指点一二。
//单端通道,不放大
#define AD_SE_ADC0 0x00 //ADC0
#define AD_SE_ADC1 0x01 //ADC1
#define AD_SE_ADC2 0x02 //ADC2
#define AD_SE_ADC3 0x03 //ADC3
#define AD_SE_ADC4 0x04 //ADC4
#define AD_SE_ADC5 0x05 //ADC5
#define AD_SE_ADC6 0x06 //ADC6
//常量定义
#define Vref 2650 //mV
/*********AD转换函数******************/
//AD转换函数
//ADC_PORT为输入的端口
/**************************************/
uint16_t Measured_Vol_INT(unsigned char ADC_PORT)
{
uint16_t M_Volt=0; //变换后的电压mV
uint32_t temp32;
uint8_t i;
ADMUX=0xC0|ADC_PORT; //片内基准电压,单端输入.
/*
ADMUX (ADC Multiplexer Select Register)
bit7 bit6
REFS1 REFS0 参考电压选择
0 0 AREF,内部Vref关闭
0 1 AVCC,AREF引脚外加滤波电容
1 0 保留
1 1 2.56V的片内基准电压源,AREF引脚外加滤波电容
bit5 ADC结果左对齐选择 1=左对齐 0=右对齐
bit4~0 选择32通道
*/
ADCSRA=(1<<ADEN)|(0<<ADSC)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
/*
ADCSRA (ADC Control and Status Register A)
bit7 ADEN ADC使能=1
bit6 ADSC 启动ADC开始转换=1
bit5 ADATE 自己触发使能
bit4 ADIF ADC中断标志
bit3 ADIE ADC中断使能
bit2:0 ADC 预分频选择位 111=128时钟分频
*/
asm ("sleep");
for(i=0;i<24;i++)
{
ADCSRA|=(1<<ADSC); //启动ADC开始转换
while ((ADCSRA&0x10)!=0x10); //等待ADC转换结束
ADCSRA|=(1<<ADIF); //写1清除标志位
ADCSRA|=~(1<<ADSC); //启动ADC开始转换
temp32=(uint32_t)ADC*Vref;
M_Volt+=(uint16_t)(temp32/1023);
}
ADCSRA&=~(1<<ADIE); //禁止ADC中断
return(M_Volt/24);
}
/****************************************/
/*主函数*/
/****************************************/
int main(void)
{
DelayMs(100); /*延时100ms*/
Lcminit(); /*液晶模块初始化 */
myprintf("mV%");
while(1)
{
DelayMs(500); /*延时500ms*/
col=0;row=2;
myprintf(" %");
col=60;row=2;
show_long((unsigned long)Measured_Vol_INT(AD_SE_ADC0));//获取端口PA0的转换数据
}
}
系统功能
大部分AVR内部带有AD,本节以使用ATMEGA16的内部AD为例,给出AD转换中断程序。
硬件设计
AVR主控电路原理图(点击图片放大,不需要放大镜!)
AD转换值低位,LED控制电路原理图(点击图片放大,不需要放大镜!)
AD转换值高位,LED控制电路原理图(点击图片放大,不需要放大镜!)
软件设计
下面部分从TXT拷出,拷到网页,代码部分缺省了很多空格,比较凌乱,请谅解!
//目标系统: 基于AVR单片机
//应用软件: ICC AVR
/*01010101010101010101010101010101010101010101010101010101010101010101
----------------------------------------------------------------------
实验内容:
使用中断检测AD0口,使用PB/PD口的LED指示AD读到的数据。
----------------------------------------------------------------------
硬件连接:
将“ADJ0.AD0”引针与“MCU.AD0” 引针使用短路帽短接。
将PB/PD口的LED指示灯使能开关切换到"ON"状态。
----------------------------------------------------------------------
注意事项:
(1)若有加载库程序,请将光盘根目录下的“库程序”下的“ICC_H”文件夹拷到D盘
(2)请详细阅读:光盘根目录下的“产品资料\开发板实验板\SMK系列\SMK1632\说明资料”
----------------------------------------------------------------------
10101010101010101010101010101010101010101010101010101010101010101010*/
#include <iom16v.h>
#include "D:\ICC_H\CmmICC.H"
#define H_VAL_DISP_DDR DDRD
#define L_VAL_DISP_DDR DDRB
#define H_VAL_DISP_PORT PORTD
#define L_VAL_DISP_PORT PORTB
const uint8 ADEnStatus[8] = {0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};
uint8 AdcMux; //ADC通道
uint16 AdcVal; //ADC转换值
/*--------------------------------------------------------------------
程序名称:AD转换初始化程序
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
void adc_init()
{
/* 设置对应的IO口为输入高阻态 */
DDRA &= ADEnStatus[AdcMux];
PORTA &= ADEnStatus[AdcMux];
ADCSRA = 0x00; //disable adc
ADMUX = (1<<REFS1)|(1<<REFS0)|(AdcMux&0x0F); //select adc input channel
ACSR = (1<<ACD); //close analog comparator
ADCSRA=(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1);
}
/*--------------------------------------------------------------------
程序名称:AD转换中断服务程序
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
AdcVal = ADC&0x3FF;
ADMUX = (1<<REFS0)|(AdcMux&0x0F); //使用 AVcc 作为ADC参考电源
ADCSRA |= (1<<ADSC); //ADSC: AD start conversion
}
/*--------------------------------------------------------------------
程序名称:
程序功能:
注意事项:
提示说明:
输 入:
返 回:
--------------------------------------------------------------------*/
void main(void)
{
H_VAL_DISP_DDR = 0xFF;
L_VAL_DISP_DDR = 0xFF;
AdcMux = 0; //使用ADC通道0
adc_init();
SEI();
while(1)
{
H_VAL_DISP_PORT = (AdcVal&0x300)>>8; //ADC的高2位Val
L_VAL_DISP_PORT = AdcVal&0xFF; //ADC的低8位Val
}
}
#include "iom16v.h"
/*20080905成功 ICC AVR 6.31A ATMEGA16
硬件连接 PA0模拟输入,接电位器抽头 PB口输出,接8个LED*/
#include <macros.h> //定义了一些常用的宏 加入20080904
#define uchar unsigned char
#pragma interrupt_handler ad_handler:15
uchar addata;
//模数转换完成中断
void ad_handler(void)
{
addata=ADCH;
PORTB=~(addata); //取反用LED显示
ADCSRA|=BIT(ADSC); //启动下一次转换 ADCSR状态寄存器 ADSC模数转换启动位
//ADCSR|=(1<<ADSC); //
}
//主程序
void main()
{
PORTA=0; //无上拉
DDRA=0; //设置PA口为输入
PORTB=0xff;
DDRB=0xff;
// ADMUX=0x00; //选择第0通道 屏蔽20080905
ADMUX=0x60; //基准AVCC,左对齐选择第0通道 加入
ADCSRA=0xCE; //采用单次转换模式,64分频
ADCSRA|=BIT(ADSC); //启动一次哑转换
//ADCSR|=(1<<ADSC); //
SREG=0x80; //开中断
ADCSRA|=BIT(ADSC); //启动一次转换
//ADCSR|=(1<<ADSC); //
while(1) //等待中断
{
;
}
}
展开阅读全文