首页 > 解决方案 > PIC16F877A 与 SIM800L

问题描述

我在使用 PIC16F877A UART 时遇到问题。我正在尝试向 SIM800L 发送 AT 命令,但它返回错误。但是当我用 CP2102 模块尝试它时,它工作正常。谁能告诉我我的代码是否有问题?

这段逻辑相似的代码在 LPC2148 上运行,但在 PIC16F877A 上出现问题。

    // CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define _XTAL_FREQ 20000000

char buff[50], a = 0;
char b, *p;
int conn=0;
int i;

#define RS RD0
#define RW RD1
#define EN RD2

void lcd_cmd(unsigned char cmd)
{
    PORTD = (0xF0 & cmd);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (cmd<<4);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_data(unsigned char data)
{
    PORTD = (0xF0 & data);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (data<<4);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_string(char *str)
{
    while(*str != '\0')
    {
        lcd_data(*str++);
    }
}

void lcd_init()
{
    lcd_cmd(0x02);//return to home
    lcd_cmd(0x28);///4bitmode
    lcd_cmd(0x0C);///cursor off
    lcd_cmd(0x06);///increment cursor
    lcd_cmd(0x01);///display clear
}


void uart_init()
{
    TXSTAbits.TXEN = 1;     ////enable transmission
    TXSTAbits.BRGH = 1;     ////high speed selection bit

    RCSTAbits.CREN = 1;     ////continuous receive enable

    SPBRG = 129;            ////baud rate generation 9600 at 20MHz crystal
    TRISCbits.TRISC7 = 1;   ////enable receive(input) on RC7
    TRISCbits.TRISC6 = 0;   ////enable transmit(output) on RC6

    RCSTAbits.SPEN = 1;     ////enable UART 

    GIE = 1;                ///enable UART related interrupts
    PEIE = 1;
    RCIE = 1;
}


void gsm_send_char(unsigned char data)
{
    TXREG = data;
    while(PIR1bits.TXIF ==0);
}

char gsm_receive_char()
{
    while(PIR1bits.RCIF == 0);
    return (RCREG);
}

void gsm_send_string(char *data)
{
    while(*data != '\0')
    {
        gsm_send_char(*data++);
    }
}

__interrupt() void uart(void)
{
    if(RCIF == 1)
    {

        b = RCREG; 
        buff[a] = b;
        a++;
        //buff[a]='\0';

        GIE = 1;
        RCIE = 1;
        PEIE = 1;
        RCIF = 0;        
    }
}

void gsm_init()
{
    if(conn == 0)
    {
        a=0;
        gsm_send_string("AT\r");
        __delay_ms(500);
        if(strstr(buff, "OK"))
        {
            lcd_cmd(0x80);
            lcd_string(buff);
            //a=0;
            memset(buff, 0, sizeof(buff));
        }

        else 
        {
            lcd_cmd(0x80);
            lcd_string("AT ERROR");
        }
    }
}

void main(void) 
{
    TRISD = 0x00;
    lcd_init();
    uart_init();

    lcd_cmd(0x80);
    lcd_string("GSM");

    while(1)
    {
        gsm_init();
        __delay_ms(2000);
    }
    return;
}

我尝试稍微更改代码并检查是否有任何错误,并尝试在标志条件下执行命令,现在它在缓冲区中没有收到任何内容,因为它没有打印任何内容。谁能告诉我为什么?

    // CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON         // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <pic16f877a.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define _XTAL_FREQ 20000000

#define RS RD0
#define RW RD1
#define EN RD2

//#define AT "AT\"

char buff[80], a;
int flag, b, i = 0;


void lcd_cmd(unsigned char cmd)
{
    PORTD = (0xF0 & cmd);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (cmd<<4 & 0xf0);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_data(unsigned char data)
{
    PORTD = (0xF0 & data);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (data<<4 & 0xf0);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_string(char *str)
{
    while(*str != '\0')
    {
        lcd_data(*str++);
    }
}

void lcd_init()
{
    lcd_cmd(0x02);//return to home
    lcd_cmd(0x28);///4bitmode
    lcd_cmd(0x0C);///cursor off
    lcd_cmd(0x01);///display clear
    lcd_cmd(0x06);///increment cursor

}

void uart_init()
{
    SPBRG = 129;
    BRGH = 1;
    SYNC = 0;
    SPEN = 1;
    TXEN = 1;
    CREN = 1;

    GIE = 1;
    PEIE = 1;
    RCIE = 1;
    RCIF = 0;
    //TXIE = 1;

    TRISC7 = 1;
    TRISC6 = 0;
}


void gsm_send_char(unsigned char data)
{
    //////////PORTB = 0xff;
    TXREG = data;
    while(PIR1bits.TXIF == 0);
}

char gsm_receive_char()
{
    while(PIR1bits.RCIF == 0);
    return RCREG;
}


void gsm_send_string(char *p)
{
    while(*p != '\0')
    {
        gsm_send_char(*p++);
    }
}


__interrupt() void isr(void)
{
    if(RCIF == 1)
    {
        a = RCREG;
        buff[i] = a;
        i++;

        if(a == '\r')
        {
            flag = 1;
        }

        if(OERR)
        {
            CREN = 0;
            CREN = 1;
        }

        if(FERR)
        {
            SPEN = 0;
            SPEN = 1;
        }
        RCIF = 0;
        ///////PORTB = 0xff;
    }
}


void main(void) 
{
    TRISD = 0x00;
    //TRISB = 0x00;

    lcd_init();
    uart_init();

    lcd_cmd(0x80);
    lcd_string("GSM TESTING");

    while(1)
    {
        if(flag == 1)
        {
        i = 0;
        gsm_send_string("AT\r\n");
        __delay_ms(400);
        if(strstr(buff, "OK"))
        {
            lcd_cmd(0xC0);
            lcd_string(buff);
            //memset(buff, 0, sizeof(buff));
        }
        else if(strstr(buff, "ERROR"))
        {
            lcd_cmd(0xC0);
            lcd_string(buff);
           // memset(buff, 0, sizeof(buff));
        }
        flag = 0;
    }
    }
    return;
}

从此链接中获取参考在此处输入链接描述

我将 PIC 直接连接到移除 SIM800L 的 PC 并运行下面的代码。当我使用腻子发送你好时,它正在打印你好。

   #include <xc.h>
#include <pic16f877a.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define _XTAL_FREQ 20000000

#define RS RD0
#define RW RD1
#define EN RD2


char buff[80], a;
int flag, b, i = 0;


void lcd_cmd(unsigned char cmd)
{
    PORTD = (0xF0 & cmd);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (cmd<<4 & 0xf0);
    RS = 0;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_data(unsigned char data)
{
    PORTD = (0xF0 & data);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;

    PORTD = (data<<4 & 0xf0);
    RS = 1;
    RW = 0;
    EN = 1;
    __delay_ms(5);
    EN = 0;
}

void lcd_string(char *str)
{
    while(*str != '\0')
    {
        lcd_data(*str++);
    }
}

void lcd_init()
{
    lcd_cmd(0x02);//return to home
    lcd_cmd(0x28);///4bitmode
    lcd_cmd(0x0C);///cursor off
    lcd_cmd(0x01);///display clear
    lcd_cmd(0x06);///increment cursor

}

void uart_init()
{
    SPBRG = 129;
    BRGH = 1;
    SYNC = 0;
    SPEN = 1;
    TXEN = 1;
    CREN = 1;

    GIE = 1;
    PEIE = 1;
    RCIE = 1;
    RCIF = 0;
    //TXIE = 1;

    TRISC7 = 1;
    TRISC6 = 0;
}

void gsm_send_char(char data)
{
    TXREG = data;
    while(TXIF == 0);

}

char gsm_receive_char()
{
    while(PIR1bits.RCIF == 0);
    return RCREG;
}


void gsm_send_string(char *p)
{
    while(*p != '\0')
    {
        gsm_send_char(*p++);
    }
}

__interrupt() void isr(void)
{
    if(RCIF == 1)
    {
        a = RCREG;
        buff[i] = a;
        i++;
        RCIF = 0;
    }
}

void main(void) 
{
    TRISD = 0x00;
    lcd_init();
    uart_init();

    lcd_cmd(0x80);
    lcd_string("GSM TESTING");

    while(1)
    {
        gsm_send_string("AT");
        __delay_ms(400);
        //i = 0;
        if(strstr(buff, "hello"))
        {
            lcd_cmd(0xC0);
            lcd_string(buff);
        }
    }
    return;
}

标签: uart

解决方案


strstr()在使用该函数之前,您需要将终止字符添加到从 UART 接收的字符串中。

像这样的东西应该工作:

    a=0;
    gsm_send_string("AT\r");
    __delay_ms(500);
    buff[sizeof(buff)-1] = '\0';        // Terminate UART buffer with NULL char
    if(strstr(buff, "OK"))
    {
        lcd_cmd(0x80);
        lcd_string(buff);
        //a=0;
        memset(buff, 0, sizeof(buff));
    }

    else 
    {
        lcd_cmd(0x80);
        lcd_string("AT ERROR");
    }

根据您使用的编译器,您可能还需要更改检查字符串中模式的方式。在我看来,最好这样做:

if(strstr(buff,"OK") != NULL)

推荐阅读