簡體   English   中英

如何在 PIC16F877A 嵌入式系統的 LCD 上顯示電壓?

[英]How to display voltages on LCD of a PIC16F877A embedded system?

我正在編寫代碼以在 PIC16F877A 的 LCD 上顯示電壓數據。 要觀察顯示屏上的值,需要延遲,但當我使用延遲 function 時,它會卡住。 當我改變鍋值時,它不會在觀察延遲期間顯示。 所以我需要幫助和指導來引入延遲。 當我改變底池的價值時,我應該在 5 秒的延遲內改變它。 我在下面分享我的代碼:

// 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

 }
}

我嘗試使用 mikroC 編譯器。

您的代碼需要完全避免延遲 - 在沒有多線程支持的延遲期間,CPU 停止執行任何有用的工作(除非在中斷處理程序中執行)。 一種解決方案(缺少 RTOS)不是延遲,而是簡單地輪詢一個自由運行的elapsed_time計數器,並執行它們變得“到期”的任何操作。

我不是 PIC 開發人員,我從各種站點上的信息中綜合了以下內容——它可能不正確,其中大部分是針對 Microchip 的 XC8 編譯器的,可能需要對 MikroC 進行一些更改——我認為它們對外設寄存器有不同的命名約定訪問結構。

因此,給定以下使用 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++ ;
    }
}

然后您可以創建一個計時器界面:

#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 ;
}

然后在您的應用程序中,例如:

    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();
        }
    }

請注意,我已通過將其設為循環中的第一個顯示來刪除不必要的初始顯示。 它可能在那里是有原因的,但我看不到它。

這可以簡化為:

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 ;
    }
}

然后

    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 ) ;
        }
    }

請注意,計時器接口允許多個不同到期時間的並發計時器,因此您可以使用如下代碼:

#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...
}

該體系結構有助於實現時間觸發的狀態機和周期性單次函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM