8051 Uart Receive sadece ilk 2 karakteri alıyor

Bowman

Aktif Üye
Katılım
7 Ekim 2022
Mesajlar
112
MS51FB9AE işlemciyi HM-10 bluetooth modülü ile kullanmaya çalışıyorum. İşlemci 8-bit 8051 mimarili bir işlemci. Telefonuma Serial Bluetooth Terminal indirdim. Bu terminal üzerinden AT komutları atıyorum. Fakat şöyle bir sorunum var. Örneğin AT+BAUD? yazıyorsam uart interruptının içindeki printf kodu alınan karakterleri AT şeklinde gösteriyor. Geri kalanını alamıyorum gibi. Sadece atıyorum 'A' karakteri geldiyse led yak gibi işlemleri yapabildim.

C:
/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* SPDX-License-Identifier: Apache-2.0                                                                     */
/* Copyright(c) 2020 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/
#include "ms51_16k.h"

#define STATE_DELAY_TIME         1000
#define RECEIVE_DATA_LENGTH          30

// Global variables
volatile uint16_t systemTick = 0;

uint8_t state = 0;
uint16_t stateFirstTime = 0;
uint16_t stateSecondTime = 0;


volatile uint8_t rxBuffer[RECEIVE_DATA_LENGTH];
volatile uint8_t index = 0;

/************************************************************************************************************/
/* PROTOTYPES                                                                                                                  */
/************************************************************************************************************/
void timer_1ms_init();
uint16_t millis();

void UART1_Init(void);
void send_at_command(void);
void analyse_data(char*);

void UART1_Write(unsigned char);
void UART1_Write_String(char*);

/************************************************************************************************************/
/* ISR FUNCTIONS                                                                                                          */
/************************************************************************************************************/
void Timer2_ISR (void) interrupt 5        // Vector @  0x2B
{
_push_(SFRS);
        systemTick++;
    clr_T2CON_TF2;
_pop_(SFRS);
}


void SerialPort1_ISR(void) interrupt 15
{
    _push_(SFRS);

    if (RI_1)
    {
            RI_1 = 0;
            uart1_receive_data = SBUF_1;
            printf("SBUF_1 = %c\r\n",SBUF_1);
            if (index < RECEIVE_DATA_LENGTH - 1)
            {   
                rxBuffer[index++] = uart1_receive_data;
                if (uart1_receive_data == '\n')
                {
                    rxBuffer[index] = '\0';
                    analyse_data(rxBuffer);
                }
            }
    }
        
        if (TI_1 == 1)
    {
        if (!PRINTFG)
        {
            clr_SCON_1_TI_1;                             /* if emission occur */
        }
    }

    _pop_(SFRS);
}

/************************************************************************************************************/
/* FUNCTION_PURPOSE: Main Loop                                                                              */
/************************************************************************************************************/
void main (void)
{
        // Init functions
    MODIFY_HIRC(HIRC_24);
    Enable_UART0_VCOM_printf_24M_115200();
        UART1_Init();
        timer_1ms_init(); 
        
        P12_PUSHPULL_MODE;
        P12 = 1;
        ENABLE_GLOBAL_INTERRUPT;
    
    
    while(1)
        {
            switch(state)
            {
                case 0:
                {
                    state = 1;
                }break;
                
                case 1:
                {
                    stateFirstTime = millis();
                    // printf("stateFirstTime = %u\r",stateFirstTime);
                    state = 2;
                }break;
                case 2:
                {
                    stateSecondTime = millis();
                    // printf("stateSecondTime = %u\n",stateSecondTime);
                    if (stateSecondTime - stateFirstTime > STATE_DELAY_TIME)
                    {
                        P12 ^= 1;
                        send_at_command();
                        state = 0;
                    }
                }break;
            }
            
        }

}


/************************************************************************************************************/
/* TIMER RELATED FUNCTIONS                                                                                        */
/************************************************************************************************************/
void timer_1ms_init()
{
    // Timer2_AutoReload_Interrupt_Initial(24,300000);
        TIMER2_DIV_128;
    TIMER2_Auto_Reload_Delay_Mode;
    RCMP2L = TIMER_DIV128_VALUE_1ms_FOSC_24000000;
    RCMP2H = TIMER_DIV128_VALUE_1ms_FOSC_24000000 >> 8;
    TL2 = 0;
    TH2 = 0;

    set_ET2;    // Set timerinterrupt
    set_TR2;    // Start timer
}

uint16_t millis()
{
    return systemTick;
}


/************************************************************************************************************/
/* UART RELATED FUNCTIONS                                                                                          */
/************************************************************************************************************/
void UART1_Init(void)
{
        P02_INPUT_MODE;
        P16_QUASI_MODE;
    UART_Open(24000000, UART1_Timer3 , 9600);
    ENABLE_UART1_INTERRUPT;
}

void send_at_command(void)
{
        UART_Send_Data(UART1,'A');
        UART_Send_Data(UART1,'T');
        UART_Send_Data(UART1,'+');
        UART_Send_Data(UART1,'B');
        UART_Send_Data(UART1,'A');
        UART_Send_Data(UART1,'U');
        UART_Send_Data(UART1,'D');
        UART_Send_Data(UART1,'?');
        UART_Send_Data(UART1,'\r');
        UART_Send_Data(UART1,'\n');
}

void UART1_Write(unsigned char dat)
{
        TI_1 = 0;
        SBUF_1 = dat;
        while (TI_1 == 0);
}

void UART1_Write_String(char* str)
{
        while (*str)
        {
                UART1_Write(*str++);
        }
}

void analyse_data(char buffer[])
{
    int i = 0;
    
    while (buffer[i] != '\0')
    {
        printf("%c",buffer[i]);
        i++;
    }
        
        printf("\n");
        
        // index = 0;
}

Kodum bu while içinde 1 saniyede 1 led yakıyorum ve AT komutunu UART1 üzerinden gönderiyorum. 8051 mimari ile hiç çalışmadım daha önce bu yüzden şu an sorunun ne olduğunu anlayamıyorum bile. Daha önce bu mimari ile çalışmış varsa problemi söyleyebilir mi acaba?
test.png

Burada art arda telefondan işlemciye AT+BAUD? stringi gönderiyorum.
 


Ben 8051 anlamam. Ama bence sorun bu RI_1 den kaynaklı olabilir. RI_1 nedir hw Bufferda veri var gibi bir bayrak mı?

Benzer sorunlar yaşamıştım. Temelde şöyle bir sorun oluyor. Veri geldiği anda kesme oluşuyor ve veriyi işlemeye başlıyorsun ancak bir yandan veri gelmeye devam ediyor. RI_1 0 set edildiğinden sonradan gelen veriler işlenmiyor. Bu değişkeni if yapısının sonunda set etmeyi deneyebilirsin. Araya iletişim hızı (1byte) kadar gecikme koyabilirsin.

Bu arada tamamen desteksiz attım...
 
Ben 8051 anlamam. Ama bence sorun bu RI_1 den kaynaklı olabilir. RI_1 nedir hw Bufferda veri var gibi bir bayrak mı?

Benzer sorunlar yaşamıştım. Temelde şöyle bir sorun oluyor. Veri geldiği anda kesme oluşuyor ve veriyi işlemeye başlıyorsun ancak bir yandan veri gelmeye devam ediyor. RI_1 0 set edildiğinden sonradan gelen veriler işlenmiyor. Bu değişkeni if yapısının sonunda set etmeyi deneyebilirsin. Araya iletişim hızı (1byte) kadar gecikme koyabilirsin.

Bu arada tamamen desteksiz attım...
RI_1 UART1'in receive interrupt bayrağı. Buffera veri gelince donanımın set ettiği bir bayrak. Ben aslında bunu if(RI_1) bloğunun sonunda sıfıra tekrar çekiyordum. Deneme yanılma sırasında geri aldım oraya.

Not: Şimdi farkettim de RI_1 bayrağını ilk olarak sıfıra çektiğimde AT karakterlerini alırken sizin dediğiniz gibi if bloğunun sonuna alınca sadece A karakterini alıyorum. Gerçekten bu bayrakla ilgili bir problemim var ama Allah bilir ne :)
 
Az çok tahmin ettiğim gibi olduğunu düşünüyorum. 8051 ile çalışan bir arkadaşım. Bu bahsettiğim gecikmeyi sağlamak için bloğun içine 3 tane nop eklemişti.
 
Çok spesifik olarak yardımcı olamam. Sadece sorunun mantığını biliyorum. Tahminimce 1byte hw buffer var. Atmge328de 1byte idi sanırım. Yerinde olsam arduino hw serial kütüphanesinin kaynak kodlarını inceleyip oradan kopya çekmeye çalışırdım.
 
Gördüğüm kadarıyla her gelen karakter için ayrı ayrı kesme gelecek şekilde yapılandırılmış seri port. Hız da 9600 baud. Bu da 900 μs de bir kesme gelecek demektir. ama senin kesme koduna bakınca, hiç de 900 μs de tamamlanacak bir koda benzemiyor. Döngüler, printf'ler, herşey var :)

Kesme kodunu komple elden geçirmen lazım. Kodun tek yaptığı şey, alınan byte'ı başka bir buffer'a koyup gerektiğinde de ana döngüdeki koda haber vermek. Öyle döngüler, printf ler, alt fonksiyon çağırmalar falan kesinlikle olmaması lazım.
 
Kesme kodunu tamamen değiştirdim. Kesme içinde sadece bufferdan veriyi okuyorum ve kendi bufferım dolmadıysa uartFlag diye bir değişkeni set ediyorum sadece. Kesme bayrağını da '\n' gelince tekrar 0 a çekiyorum.

C:
/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* SPDX-License-Identifier: Apache-2.0                                                                     */
/* Copyright(c) 2020 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/
#include "ms51_16k.h"

#define STATE_DELAY_TIME         1000
#define RECEIVE_DATA_LENGTH          30

// Global variables
volatile uint16_t systemTick = 0;

uint8_t state = 0;
uint16_t stateFirstTime = 0;
uint16_t stateSecondTime = 0;


uint8_t rxBuffer[RECEIVE_DATA_LENGTH];
uint8_t index = 0;
volatile uint8_t uartFlag = 0;

/************************************************************************************************************/
/* PROTOTYPES                                                                                                                  */
/************************************************************************************************************/
void timer_1ms_init();
uint16_t millis();

void UART1_Init(void);
void send_at_command(void);
void analyse_data(char*);


/************************************************************************************************************/
/* ISR FUNCTIONS                                                                                                          */
/************************************************************************************************************/
void Timer2_ISR (void) interrupt 5        // Vector @  0x2B
{
_push_(SFRS);
        systemTick++;
    clr_T2CON_TF2;
_pop_(SFRS);
}


void SerialPort1_ISR(void) interrupt 15
{
    _push_(SFRS);
      
    if (RI_1)
    {
            uart1_receive_data = SBUF_1;
            if (index < RECEIVE_DATA_LENGTH - 1)
            {
                uartFlag = 1;
            }
        }
          
      
        if (TI_1 == 1)
    {
        if (!PRINTFG)
        {
            clr_SCON_1_TI_1;                             /* if emission occur */
        }
    }

    _pop_(SFRS);
}

/************************************************************************************************************/
/* FUNCTION_PURPOSE: Main Loop                                                                              */
/************************************************************************************************************/
void main (void)
{
        // Init functions
    MODIFY_HIRC(HIRC_24);
    Enable_UART0_VCOM_printf_24M_115200();
        UART1_Init();
        timer_1ms_init();        // led blink on electronic board
      
        P12_PUSHPULL_MODE;
        P12 = 1;
        ENABLE_GLOBAL_INTERRUPT;
  
  
    while(1)
        {
            if (uartFlag)
            {
                rxBuffer[index++] = uart1_receive_data;
                printf("uart1_receive_data = %c\n",uart1_receive_data);
                if (uart1_receive_data == '\n')
                {
                    RI_1 = 0;
                    rxBuffer[index] = '\0';
                    analyse_data(rxBuffer);
                    index = 0;
                }
                uartFlag = 0;
            }
          
            switch(state)
            {
                case 0:
                {
                    state = 1;
                }break;
              
                case 1:
                {
                    stateFirstTime = millis();
                    // printf("stateFirstTime = %u\r",stateFirstTime);
                    state = 2;
                }break;
                case 2:
                {
                    stateSecondTime = millis();
                    // printf("stateSecondTime = %u\n",stateSecondTime);
                    if (stateSecondTime - stateFirstTime > STATE_DELAY_TIME)
                    {
                        P12 ^= 1;
                        send_at_command();
                        state = 0;
                    }
                }break;
            }     
        }

}


/************************************************************************************************************/
/* TIMER RELATED FUNCTIONS                                                                                        */
/************************************************************************************************************/
void timer_1ms_init()
{
    // Timer2_AutoReload_Interrupt_Initial(24,300000);
        TIMER2_DIV_128;
    TIMER2_Auto_Reload_Delay_Mode;
    RCMP2L = TIMER_DIV128_VALUE_1ms_FOSC_24000000;
    RCMP2H = TIMER_DIV128_VALUE_1ms_FOSC_24000000 >> 8;
    TL2 = 0;
    TH2 = 0;

    set_ET2;    // Set timerinterrupt
    set_TR2;    // Start timer
}

uint16_t millis()
{
    return systemTick;
}


/************************************************************************************************************/
/* UART RELATED FUNCTIONS                                                                                          */
/************************************************************************************************************/
void UART1_Init(void)
{
        P02_INPUT_MODE;
        P16_QUASI_MODE;
    UART_Open(24000000, UART1_Timer3 , 9600);
    ENABLE_UART1_INTERRUPT;
}

void send_at_command(void)
{
        UART_Send_Data(UART1,'A');
        UART_Send_Data(UART1,'T');
        UART_Send_Data(UART1,'+');
        UART_Send_Data(UART1,'B');
        UART_Send_Data(UART1,'A');
        UART_Send_Data(UART1,'U');
        UART_Send_Data(UART1,'D');
        UART_Send_Data(UART1,'?');
        UART_Send_Data(UART1,'\r');
        UART_Send_Data(UART1,'\n');
}

void analyse_data(char buffer[])
{
    int i = 0;
  
    while (buffer[i] != '\0')
    {
        printf("%c",buffer[i]);
        i++;
    }
      
        printf("\n");
      
        // index = 0;
}
Bu kodun artık yeni hali uart kesme içinde yaptığım işi sonsu döngüye taşıdım. Fiziksel olarak HM-10'un VCC'si işlemci VCCsine, GNDsi işlemci GNDsine, TX'i işlemci RX'ine direkt olarak bağlı. HM-10 RX pininde 1.2k-2.4k olacak şekilde bir gerilim bölücü var. İlk aşamada telefondan bağlanmayıp direkt modülle UART1 üzerinden konuşmak istiyorum. Putty ekranında hiçbir şey gözükmüyor malesef anlamadım gitti
 
Programı öncelikle kafanda çalıştırıp çalıştığını görmen lazım. Bir nevi simulatör gibi, ağır çekimde :)

Şimdi senin yeni kesme koduna bakıyorum, tek yaptığı şey, seri porttan okunan datayı bir değişkene yazmak ve flag set etmek. Ama dediğim gibi, her 900 μs de yeni kesme geliyor. Bu süre içinde ana kodun bu datayı işleyebileceğinin bir garantisi var mı? Yok. Hatta çok büyük ihtimalle işleyemez. O senin değişkene üst üste onlarca veri yazar kesme, sonra da senin ana program gelir ve en son ne yazılmışsa onu okur ve haberi bile olmaz onlarca byte kaçırdığından.

Yapılması gereken şu: kesme, byte'ları bir buffer içerisinde biriktirecek. Ana program da bu buffer üzerinde byte'ları işleyecek. Burada değişik uygulamalar yapılabilir, ama ben olsam işi "head/tail circular queue" denen yapı ile çözerim. ISR head üzerinden yazıyor, ana kod tail üzerinden okuyor. Bunu araştır.
 
Eğer elinde dijital osiloskop varsa, hem problemi gözlemleyebilirsin hem de bir çözüm getirdiğinde çözümün uygun olduğunu doğrulayabilirsin.

Kesme girişinde bir GPIO set et, çıkışında clear et.

Ama program satırı gördüğünde başka bir GPIO set et, satırı işledikten sonra clear et.

Sonra da osiloskop ile bu iki sinyale bak. Eğer osiloskopta 4 kanal varsa ve protokol çözümleme de varsa tam şamda kayısı :D iki osiloskop kanalı UART TX/RX e bakar ve çözümler, bir kanal kesmeye bakar, bir kanal de ana programın satır işleme koduna bakar.
 
Bugün şunu farkettim. Bu arkadaşların uart kütüphanelerinde printf ile buffera ne yazdığıma bakmak isterken aslında buffera veri gitmediğini gördüm. Bu fonksiyonu uart üzerinden veri göndermek için kullanıyorum. printf fonksiyonlarının çıktısı ekran görüntüsündeki gibi. Bu benim aslında veriyi buffera yazamadığım anlamına mı geliyor?

C:
void UART_Send_Data(unsigned char UARTPort, unsigned char c)
{
    _push_(SFRS);
    SFRS = 0;
    switch (UARTPort)
    {
        case UART0:
          TI=0;
          SBUF = c;
          while(!TI);
        break;
        case UART1:
            TI_1 = 0;
            SBUF_1 = c;
            printf("SBUF_1 = %c\n",SBUF_1);
            printf("c = %c\n",c);
            while (!TI_1);
        break;
    }
    _pop_(SFRS);
}

debug.png
 

Çevrimiçi personel

Forum istatistikleri

Konular
6,956
Mesajlar
118,801
Üyeler
2,825
Son üye
karahanli7

Son kaynaklar

Son profil mesajları

hakan8470 wrote on Dede's profile.
1717172721760.png
Dedecim bu gul mu karanfil mi? Gerci ne farkeder onu da anlamam. Gerci bunun anlamini da bilmem :gulus2:
Lyewor_ wrote on hakan8470's profile.
Takip edilmeye başlanmışım :D ❤️
Merhaba elektronik tutsakları...
Lyewor_ wrote on taydin's profile.
Merhabalar. Elektrik laboratuvarınız varsa bunun hakkında bir konunuz var mı acaba? Sizin laboratuvarınızı merak ettim de :)
Lyewor_ wrote on taydin's profile.
Merhabalar forumda yeniyim! Bir sorum olacaktı lcr meterler hakkında. Hem bobini ölçen hemde bobin direnci ölçen bir lcr meter var mı acaba?
Back
Top