PIC16F877A嵌入式系统LCD电压显示及延时卡顿问题求助
问题:PIC16F877A LCD显示中延时阻塞ADC采样的解决方法
我用mikroC编译器编写PIC16F877A的LCD电压数据显示代码,需要5秒延时来校准输入电压,但调用delay_ms()会导致系统卡顿,调节电位器时数值在延时期间无法更新——因为延时阻塞了ADC采样。附上代码:
// Lcd pinout settings sbit LED1 at RB4_bit; sbit LCD_RS at RD2_bit; sbit LCD_EN at RD3_bit; sbit LCD_D4 at RD4_bit; sbit LCD_D5 at RD5_bit; sbit LCD_D6 at RD6_bit; sbit LCD_D7 at RD7_bit; //sbit SW at RB1_bit; // Pin direction sbit LCD_RS_Direction at TRISD2_bit; sbit LCD_EN_Direction at TRISD3_bit; sbit LCD_D4_Direction at TRISD4_bit; sbit LCD_D5_Direction at TRISD5_bit; sbit LCD_D6_Direction at TRISD6_bit; sbit LCD_D7_Direction at TRISD7_bit; unsigned short count,pls; unsigned char ch,bh; long tlong,blong; void adc1_config(); void adc2_config(); int adc1_prcs(); int adc2_prcs(); void main() { adc1_config(); adc2_config(); ADC_Init(); Lcd_Init(); Lcd_Cmd(_LCD_CLEAR); Lcd_Cmd(_LCD_CURSOR_OFF); adc1_prcs(); adc2_prcs(); Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); delay_ms(5000); // here i want delay to adjust input voltage and calibrate. // delay does not work here bcoz adc value stuck due to delay function. // suugest proven technique to avoid delay. TRISB.F4 = 0; while(1) { Lcd_Out(1,1,"info page"); Lcd_Out(2,4,"123456789"); delay_ms(5000); //same scenario occur here Lcd_Cmd(_LCD_CLEAR); adc1_prcs(); adc2_prcs(); Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); delay_ms(5000); Lcd_Cmd(_LCD_CLEAR); // and here also } }
解决方案
方法1:软件计时轮询法(无需定时器)
核心逻辑是用全局变量累计计时,主循环中不断检查是否达到延时时长,同时穿插执行ADC采样,保证数值实时更新。
修改后的主函数示例:
unsigned long timer_count = 0; unsigned char display_state = 0; // 0:校准界面, 1:信息页面, 2:电压显示页面 void main() { adc1_config(); adc2_config(); ADC_Init(); Lcd_Init(); Lcd_Cmd(_LCD_CLEAR); Lcd_Cmd(_LCD_CURSOR_OFF); TRISB.F4 = 0; // 初始校准界面 Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); timer_count = 0; display_state = 0; while(1) { // 持续执行ADC采样,实时更新数值 adc1_prcs(); adc2_prcs(); // 此处可添加实时刷新LCD电压值的代码 // 1ms计时累加 delay_ms(1); timer_count++; switch(display_state) { case 0: // 校准界面等待5秒 if(timer_count >= 5000) { timer_count = 0; display_state = 1; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"info page"); Lcd_Out(2,4,"123456789"); } break; case 1: // 信息页面等待5秒 if(timer_count >= 5000) { timer_count = 0; display_state = 2; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); } break; case 2: // 电压显示页面等待5秒 if(timer_count >= 5000) { timer_count = 0; display_state = 1; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"info page"); Lcd_Out(2,4,"123456789"); } break; } } }
方法2:定时器中断法(精准高效)
利用PIC16F877A的Timer0产生1ms中断,在中断中累计计时,主循环仅检查计时变量,同时持续执行ADC采样。
配置Timer0和中断的示例代码:
unsigned long timer_ticks = 0; unsigned char display_state = 0; // 中断服务函数 void interrupt() { if(TMR0IF_bit) // Timer0溢出中断触发 { TMR0 = 0x63; // 预加载值(8MHz晶振下对应1ms中断,需根据实际晶振调整) TMR0IF_bit = 0; // 清除中断标志 timer_ticks++; } } void main() { // 配置Timer0 OPTION_REG = 0b00000111; // 预分频器1:256,内部时钟源 TMR0 = 0x63; TMR0IE_bit = 1; // 使能Timer0中断 GIE_bit = 1; // 全局中断使能 adc1_config(); adc2_config(); ADC_Init(); Lcd_Init(); Lcd_Cmd(_LCD_CLEAR); Lcd_Cmd(_LCD_CURSOR_OFF); TRISB.F4 = 0; // 初始校准界面 Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); timer_ticks = 0; display_state = 0; while(1) { // 持续执行ADC采样,实时更新数值 adc1_prcs(); adc2_prcs(); // 此处可添加实时刷新LCD电压值的代码 switch(display_state) { case 0: if(timer_ticks >= 5000) { timer_ticks = 0; display_state = 1; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"info page"); Lcd_Out(2,4,"123456789"); } break; case 1: if(timer_ticks >= 5000) { timer_ticks = 0; display_state = 2; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"VAC-IN : "); Lcd_Out(2,1,"VAC-OUT: "); } break; case 2: if(timer_ticks >= 5000) { timer_ticks = 0; display_state = 1; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,1,"info page"); Lcd_Out(2,4,"123456789"); } break; } } }
关键说明
- 两种方法均替代了阻塞式
delay_ms(),主循环始终运行,ADC采样可持续进行,调节电位器时数值会实时更新 - 方法1实现简单,无需配置中断,但
delay_ms(1)会占用少量CPU资源;方法2计时精准,主循环可专注处理其他任务
内容的提问来源于stack exchange,提问作者Afzal Ansari
相关产品推荐
相关产品推荐

