[英]How to display voltages on LCD of a PIC16F877A embedded system?
I am writing code to display voltage data on the LCD on a PIC16F877A.我正在编写代码以在 PIC16F877A 的 LCD 上显示电压数据。 To observe the values on the display, it needs a delay but when I use the delay function, it gets stuck.要观察显示屏上的值,需要延迟,但当我使用延迟 function 时,它会卡住。 When I change the pot value, it will not show during the observation delay.当我改变锅值时,它不会在观察延迟期间显示。 So I need assistance and guidance to introduce delay.所以我需要帮助和指导来引入延迟。 When I change the value of the pot, I should change it during a 5 second delay.当我改变底池的价值时,我应该在 5 秒的延迟内改变它。 I share my code below:我在下面分享我的代码:
// 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
}
}
I tried using the mikroC compiler.我尝试使用 mikroC 编译器。
Your code needs to avoid delay altogether - during a delay without multi-threading support, the CPU stalls doing no useful work (unless performed in interrupt handlers).您的代码需要完全避免延迟 - 在没有多线程支持的延迟期间,CPU 停止执行任何有用的工作(除非在中断处理程序中执行)。 One solution to that (short of an RTOS) is rather than delay, simply poll a free-running counter of elapsed_time and perform actions whatever they become " due ".一种解决方案(缺少 RTOS)不是延迟,而是简单地轮询一个自由运行的elapsed_time计数器,并执行它们变得“到期”的任何操作。
I am no PIC developer and I have synthesised the following from information on various sites - it may not be correct and most of it was for Microchip's XC8 compiler and may need some changes for MikroC - I think they have a different naming convention for peripheral register access structures.我不是 PIC 开发人员,我从各种站点上的信息中综合了以下内容——它可能不正确,其中大部分是针对 Microchip 的 XC8 编译器的,可能需要对 MikroC 进行一些更改——我认为它们对外设寄存器有不同的命名约定访问结构。
So given the following 1ms tick implementation using TIMER 0:因此,给定以下使用 TIMER 0 的 1ms 节拍实现:
#define FOSC_FREQ 4000000 //4MHz
// 1/1000 seconds 24=56 prescaler
#define TIMER_1MS (256 - FOSC_FREQ / (1024 * 1000) )
static volatile uint32_t ms_tick = 0 ;
uint32_t initMsTick()
{
OPTION_REGbits.PSA = 0;
OPTION_REGbits.PS = 0b111; //Set the prescaler to 1:256
OPTION_REGbits.T0CS = 0;
INTCONbits.T0IF = 0; //Clear the Timer 0 interrupt flag
TMR0 = TIMER_1MS; //Load counter for 1ms tick
INTCONbits.T0IE = 1; //Enable the Timer 0 interrupt
INTCONbits.GIE = 1; //Set the Global Interrupt Enable
}
uint32_t getMsTick()
{
uint32_t now = ms_tick ;
while( now != ms_tick )
{
now = ms_tick ;
}
return now ;
}
void interrupt()
{
if( INTCONbits.T0IF)
{
INTCONbits.T0IF = TIMER_1MS ;
ms_tick++ ;
}
}
you might then create a timer interface thus:然后您可以创建一个计时器界面:
#include <stdbool.h>
typedef struct
{
uint32_t ref ;
uinr32_t period ;
} timer_t ;
void startTimer( timet_t* timer, uint32_t period )
{
timet->ref = getMsTick() ;
timer->period = period ;
}
bool hasTimerExpired( timer_t* timer )
{
return (getMsTick() - timer->ref) >= timer->period ;
}
Then in your application for example:然后在您的应用程序中,例如:
adc1_config();
adc2_config();
ADC_Init();
Lcd_Init();
Lcd_Cmd(_LCD_CURSOR_OFF);
TRISB.F4 = 0;
timer_t display_time ;
for(;;)
{
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"VAC-IN : ");
Lcd_Out(2,1,"VAC-OUT: ");
startTimer( &display_time, 4000u ) ;
while( !hasTimerExpired( &display_time ) )
{
adc1_prcs();
adc2_prcs();
}
Lcd_Cmd(_LCD_CLEAR);
Lcd_Out(1,1,"info page");
Lcd_Out(2,4,"123456789");
timer_t display_time ;
startTimer( &display_time, 4000u ) ;
while( !hasTimerExpired( &display_time ) )
{
adc1_prcs();
adc2_prcs();
}
}
Note that I have removed your unnecessary initial display by making it the first display in the loop.请注意,我已通过将其设为循环中的第一个显示来删除不必要的初始显示。 It may have been there for a reason, but I cannot see it.它可能在那里是有原因的,但我看不到它。
This can be simplified given:这可以简化为:
void displayPage( int page )
{
Lcd_Cmd(_LCD_CLEAR);
switch( page )
{
case 0 :
{
Lcd_Out(1,1,"VAC-IN : ");
Lcd_Out(2,1,"VAC-OUT: ");
}
break ;
case 1 :
{
Lcd_Out(1,1,"info page");
Lcd_Out(2,4,"123456789");
}
break ;
}
}
then然后
int page = 0 ;
displayPage( page ) ;
timer_t display_time ;
startTimer( &display_time, 4000u ) ;
for(;;)
{
// Read ADCs continuously
adc1_prcs();
adc2_prcs();
// Every four seconds flip display
if( hasTimerExpired( &display_timer ) )
{
startTimer( &display_time, 4000u )
page = page == 0 ? 1 : 0 ;
displayPage( page ) ;
}
}
Note that the timer interface allows multiple concurrent timers of differing expiry periods so that you can have code like:请注意,计时器接口允许多个不同到期时间的并发计时器,因此您可以使用如下代码:
#define TASK1_PERIOD 1000u ; // 1 second
#define TASK2_PERIOD 333u ; // 1/3 second
timet_t t1, t2 ;
startTimer( &t1, TASK1_PERIOD ) ;
startTimer( &t2, TASK2_PERIOD ) ; // 1/3 second
for(;;)
{
if( hasTimerExpired( &t1 ) )
{
startTimer( &t1, TASK1_PERIOD ) ; // restart
// Things to do every second here...
}
if( hasTimerExpired( &t2 ) )
{
startTimer( &t2, TASK2_PERIOD ) ; // restart
// Things to do every 1/3 second here...
}
// Things to do continuously here...
}
The architecture lends itself to implementing time-triggered state-machines, and periodic single-shot functions.该体系结构有助于实现时间触发的状态机和周期性单次函数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.