📄 main._c
字号:
#include <iom16v.h>
#include <macros.h>
#include "lcd.h"
#include "usart.h"
#include "delay.h"
#define vref 256
volatile unsigned int extint_count=0;
volatile unsigned char act_flag=0;
volatile unsigned int adc_result;
unsigned char adc_show[6];
/** /
volatile:数据类型声明,表明该变量在程序执行中可被隐含改变
编译器有时会将SRAM中的数据拷贝到通用寄存器中以提高程序的执行效率
(在通用寄存器中对数据的操作速度比操作SRAM中的数据要快),这样会带来
一个问题,如果该SRAM中的数据已经被隐含改变(比如中断),那么编译器仍然
读取寄存器中之前的SRAM拷贝值显然与其实际值不同,从而出现错误。
本例中extint_count的值在外部中断服务程序中被改变,通过volatile
声明通知编译器。
/**/
/** /
MCUCR &= 0X40; //将休眠模式清0,即休眠模式1
MCUCR |= 0X10; //将休眠模式为1,即休眠模式2
/**/
void port_init(void)
{
PORTA = 0xFE;
DDRA = 0xFE;
PORTB = 0xFF;
DDRB = 0xFF;
PORTC = 0xFF;
DDRC = 0xFF;
DDRD = 0xFB; //PD2(INT0)引脚设置为输入
PORTD = 0xFB; //关闭内部上拉
}
/* AD转换程序 */
#pragma interrupt_handler adc_isr:15
void adc_isr(void)
{
unsigned int temp=0;
while(temp<6)
temp++; //短延时
adc_result = ADC; //读取AD转换值
//ADCSRA |= (1<<ADSC); //再次启动转换
}
void data_con(void)
{
unsigned int temp;
unsigned char i;
temp=(unsigned int)(((unsigned long)((unsigned long)adc_result*vref))/1024);
for(i=0;i<3;i++)
{
adc_show[3-i]=temp%10+0x30; //转换电压值用来在LCD上显示
temp=temp/10;
}
adc_show[0]=adc_show[1];
adc_show[1]='.';
adc_show[4]='V';
adc_show[5]=0; //数组结束标记
}
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{
extint_count++;
if (act_flag!=1)
{
act_flag = 1;
}
}
void adc_init(void)
{
ADMUX = (1<<REFS1)|
(1<<REFS0)| //选择内部2.56v作为参考电压
0x00; //使用ad转换0通道
//ADLAR = 0,转换结果选择右对齐
ADCSRA = //(1<<ADEN)| //ADC使能
//(1<<ADSC)| //开始一次ad转换
(1<<ADIF)| //写1,将ADIF位清0
(1<<ADIE)| //允许ADC中断
0x06; //时钟分频系数为64
}
void sleep_init(void)
{
MCUCR |= 0X40; //使能休眠
}
//call this routine to initialize all peripherals
void init_devices(void)
{
CLI(); //关闭全局中断
port_init(); //CPU端口初始化
/** /
MCUCR = 0x02; //INT0引脚上的下降沿触发中断
GICR = 0x40; //外部中断0请求使能
/**/
/**/
MCUCR = 0x00; //INT0引脚上的低电平触发中断
GICR = 0x40; //外部中断0请求使能
/**/
/** /
MCUCR = 0x01; //INT0引脚上的上升沿和下降沿都触发中断
GICR = 0x40; //外部中断0请求使能
/**/
/** /
MCUCR = 0x03; //INT0引脚上的上升沿触发中断
GICR = 0x40; //外部中断0请求使能
/**/
adc_init();
sleep_init();
SEI(); //打开全局中断
}
void main(void)
{
char temp_show[5]; //定义数组用作在液晶屏上进行显示
unsigned char i;
unsigned int temp;
for(i=0;i<5;i++)
{
temp_show[i] = 0;
}
temp_show[4] = 0xff; //显示结束标志
/**/
init_devices();
LCDReady();
LcdInit(); //LCD初始化
CharsWrite(0,1,"SYSTEM INIT"); //在LCD的第一行显示"SYSTEM INIT"
CharsWrite(0,2,"......"); //在第二行显示“......”
uart_init(); //串口初始化
delay_ms(1000);
/**/
while(1)
{
ClearLcd(); //清屏LCD
delay_us(80); //等待清屏操作完成
CharsWrite(0,1,"SLEEP IN IDLE");
MCUCR &= 0X40; ////将休眠模式位清0,即休眠模式1
asm("sleep"); //在线嵌入汇编,CPU进入idle休眠模式
//等待外部中断唤醒
PORTA = 0X00; //点亮PA口LED
CharsWrite(0,2,"NOW MCU WAKEUP");
delay_ms(5000);
PORTA = 0XFF; //55秒钟后熄灭PA口LED
//测试ADC噪声抑制模式
ClearLcd(); //清屏LCD
delay_us(80); //等待清屏操作完成
ADCSRA |= (1<<ADEN); //使能ADC
CharsWrite(0,1,"SLEEP IN ADC:"); //在LCD的第一行显示"SLEEP IN ADC"
MCUCR &= 0X40;
MCUCR |= 0X10; //将休眠模式位送1,即休眠模式2,ADC噪声抑制模式
asm("sleep"); //在线嵌入汇编,CPU进入ADC休眠模式
//在此模式下,进入休眠会自动启动一次AD转换,转换完成中断将唤醒MCU
PORTA = 0X00; //ADC转换完成唤醒MCU,点亮PA口LED
CharsWrite(0,2,"NOW MCU WAKEUP");
delay_ms(5000);
PORTA = 0XFF; //5秒钟后显示AD转换结果
data_con(); //将ad转换值转换为电压值
ClearLcd(); //清屏LCD
delay_us(80); //等待清屏操作完成
CharsWrite(0,1,"ADO VOLTAGE:");
CharsWrite(0,2,adc_show); //在LCD上显示转换电压值
delay_ms(5000);
ADCSRA &=~ (1<<ADEN); //禁止ADC,因为进入IDLE模式,如果ADC被使能,
//也将开始一次AD转换
ClearLcd(); //清屏LCD
delay_us(80); //等待清屏操作完成
CharsWrite(0,1,"POWERDOWN MODE");
MCUCR &= 0X40;
MCUCR |= 0X20; //将休眠模式位送1,即休眠模式2,ADC噪声抑制模式
asm("sleep"); //在线嵌入汇编,CPU进入掉电休眠模式
//等待外部中断唤醒
PORTA = 0X00; //点亮PA口LED
CharsWrite(0,2,"NOW MCU WAKEUP");
delay_ms(5000);
PORTA = 0XFF; //1秒钟后熄灭PA口LED
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -