找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5386|回復(fù): 1
打印 上一主題 下一主題
收起左側(cè)

PIC16F1937-PC通訊協(xié)議

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:105323 發(fā)表于 2016-2-21 18:57 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
main.c
/****************************************************************************/
/*                                                                          */
/*                Copyright (c) 2016, 老馬工作室                            */
/*                     All rights reserved.                                 */
/*                                                                          */
/*      Email:pcwebmaster@163.com                                           */
/****************************************************************************/
/****************************************************************************/
/* 文 件 名:comint.c                                                       */
/* 版    本:Version 1.0                                                    */
/* 描    述:串行口中斷帶通訊協(xié)議測試                                       */
/* 主控芯片:PIC16F1937                                                                                                                */
/* 晶振頻率:4MHz                                                                                                                */
/* 作    者:pcwebmaster(北極狼)                                            */
/* 函    數(shù):                                                               */
/*                 system_init                                                     */
/*                 com_send_command                                                */
/*                 com_command_receive                                                                                                */
/*                        CalCRC16_1021                                                                                                        */
/*                        command_decoder                                                                                                        */
/*                        send_command                                                                                                        */
/* 測    試: 發(fā)送:16 16 02 01 02 01 00 35 03 94 BD接收:49 AA 15                        */
/* 測試現(xiàn)象:                                                                                                                                */
/* 歷史記錄:20016.02.19測試通過                                            */
/* 北極狼          20016-02-19     Creat Inital version. (Version 1.0)      */
/****************************************************************************/
#include "pic.h"
#include "comint.h"
__CONFIG(FOSC_INTOSC&CLKOUTEN_OFF&MCLRE_ON&WDTE_OFF);//&PWRTE_ON&BOREN_ON

#define _XTAL_FREQ      4000000L            //內(nèi)部4MHz

//*******************************************************************//
//                          系統(tǒng)初始化
//*******************************************************************//
void System_Init(void)
{
        OSCCON = 0b01101000;            //內(nèi)部4MHz
        OSCTUNE= 0b00000000;            //出廠校準
        ADCON1 = 0b10110000;            //內(nèi)部Frc Vref = VDD
        ADCON0 = 0b00010001;            //ADON = 1 As AN4

        TRISA  = 0b00100000;            //RA0-RA3輸出、RA5輸入
        ANSELA = 0b00100000;            //RA5 模擬輸入  
                  
        TRISB  = 0b00001111;            //RB0-RB3觸摸按鍵
        ANSELB = 0b00001111;            //4個觸摸按鍵
        WPUB   = 0b00000000;            //無上拉

        IOCBP  = 0b00000000;            //關(guān)電平變化中斷
        IOCBN  = 0b00000000;
        
        TRISD  = 0b00000000;            //PORTD輸出
        ANSELD = 0b00000000;            //數(shù)字  I/O

        TRISC  = 0b10011000;            //串口 I2C

        TRISE  = 0b00000000;            //PORTE輸出
        ANSELE = 0b00000000;            //數(shù)字  I/O
        WPUE   = 0b00000000;            //無上拉
        
        LATA  = 0x00;
        LATB  = 0x00;
        LATC  = 0x00;
        LATD  = 0x00;
        LATE  = 0x00;
}
//*******************************************************************//
//                    TMR0定時初始化
//*******************************************************************//
void TMR0_Init(void)
{
        OPTION_REG = 0b11010011;        
        TMR0IF = 0;
        TMR0IE = 1;
}

//*******************************************************************//
//                             主程序部分
//*******************************************************************//

void main(void)
{
        INT8U *str="Hello World! \n\rSerial test normal\n\r";
        INT8U *end="\n\r";
        __delay_ms(10);
        System_Init();          //系統(tǒng)初始化
        CLRWDT();               //WDT看門狗
        TMR0_Init();            //TMR0初始化
        Serial_port_init();                //UART初始化
        PEIE = 1;               //外設(shè)中斷允許
        GIE = 1;                //總中斷允許
        buff_init();
        Send_String(str);
        Send_String(end);
        while (1)
        {
                com_command_receive();  
        }
}

COMINT.C
/****************************************************************************/
/*                                                                          */
/*                Copyright (c) 2016, 老馬工作室                            */
/*                     All rights reserved.                                 */
/*                                                                          */
/*      Email:pcwebmaster@163.com                                           */
/****************************************************************************/
/****************************************************************************/
/* 文 件 名:comint.c                                                       */
/* 版    本:Version 1.0                                                    */
/* 描    述:串行口中斷帶通訊協(xié)議測試                                       */
/* 主控芯片:PIC16F1937                                                                                                                */
/* 晶振頻率:4MHz                                                                                                                */
/* 作    者:pcwebmaster(北極狼)                                            */
/* 函    數(shù):                                                               */
/*                 system_init                                                     */
/*                 com_send_command                                                */
/*                 com_command_receive                                                                                                */
/*                        CalCRC16_1021                                                                                                        */
/*                        command_decoder                                                                                                        */
/*                        send_command                                                                                                        */
/* 測    試: 發(fā)送:16 16 02 01 02 01 00 35 03 94 BD接收:49 AA 15                        */
/* 測試現(xiàn)象:                                                                                                                                */
/* 歷史記錄:20016.02.19測試通過                                            */
/* 北極狼          20016-02-19     Creat Inital version. (Version 1.0)      */
/****************************************************************************/
#include <pic.h>
#include "comint.h"


uint8_t  pint_buf[MAX_RINTL];   /* 串口接收緩沖區(qū)       */
uint8_t  pint_read;             /* 串口緩沖區(qū)讀指針     */
uint8_t  pint_write;            /* 串口緩沖區(qū)寫指針     */
//uint8_t  psend_int;             /* 串口發(fā)送允許標志     */
uint8_t  serial_flag = 0;       /* 串口接收數(shù)據(jù)標志位   */


uint8_t  prec_buf[MAX_COMMAND_LEN];                /* 命令接收緩沖區(qū)    */
uint8_t  prec_num;                    /* 命令接收緩沖區(qū)字節(jié)數(shù) */

uint8_t serial_lengthl = 0;           /* 消息命令長度低8位    */
uint16_t  serial_length = 0;          /* 消息命令長度16位     */

uint8_t ADDRESS[2]={ZU,ZHAN};               /* byte0:通訊組地址, byte1:開發(fā)板地址 */

//-----------------------------------------------------------------
// 串口初始化
//-----------------------------------------------------------------
void Serial_port_init(void)
{
        unsigned char BaudRate = 0;
        BaudRate = BAUDRATE;
        switch(BaudRate)
        {
                case 1:
                                BRGH = 0;               //2400
                                SPBRG = 25;
                                break;
                case 2:
                                BRGH = 0;               //4800
                                SPBRG = 12;
                                break;
                case 3:
                                BRGH = 1;               //9600
                                SPBRG = 25;
                                break;
                case 4:
                                BRGH = 1;               //19200
                                SPBRG = 12;
                                break;
        }
        SYNC = 0;              // asynchronous
        SPEN = 1;              // enable serial port pins
        CREN = 1;              // enable reception
        TXEN = 1;         // enable Send
        SREN = 0;              // no effect
        TXIE = 0;         // Disable TX interrupts
        RCIE = 1;         // Enable  RX interrupts
}
//-----------------------------------------------------------------
// 串口發(fā)送一個字節(jié)
//-----------------------------------------------------------------
void com_send_command(char Onebyte)
{
        TXREG = Onebyte;
        while(TRMT);
        __delay_ms(1);//4M晶體最少需要1MS延時,??
}

//------------------------------------------------------------------
// (串口接收)中斷程序(緩沖滿時數(shù)據(jù)前移)
//------------------------------------------------------------------
void interrupt Serial_Port_Recv_ISR(void)
{
    uint8_t temp;
    uint8_t temp1;
        if(TMR0IE && TMR0IF)                   //4MHz  2.5ms
        {
                TMR0IF = 0;
                TMR0 = 0x65;
                CLRWDT();
        }        
        if(RCIE && RCIF)
        {
                temp1 = RCREG;                         //讀取數(shù)據(jù)
                temp  = pint_write + 1; /* 判斷是否可以寫入 */
                if (temp == MAX_RINTL)
                {
                                temp=0;
                }
                if (temp != pint_read)
                {
                                pint_buf[pint_write] = temp1; /* 讀取數(shù)據(jù) */
                                pint_write = temp;
                }                        
        }        
}

void buff_init(void)
{
    uint8_t loop;
    loop = RCREG;   /* 清串口緩沖區(qū)   */
    for (loop=0; loop<MAX_RINTL; loop++)
    {
        pint_buf[loop] = 0;
    }
}
////////////////////////////以上需要修改移植,以下直接移植并添加代碼/////////////////////////////////////////////
//------------------------------------------------------------------
// 向PC機發(fā)送字符串
//------------------------------------------------------------------
void Send_String(char *str)
{
        while(*str)                  //檢測str是否有有效
        {
                com_send_command(*str++);
        }
}
/* 串口接收數(shù)據(jù)處理 */
void com_command_receive(void)
{
    uint8_t var1,var4;
    uint16_t crc_data = 0;
    var4 = pint_read;

    if (var4 != pint_write)
    {
        var1 = pint_buf[var4];
        var4 = var4+1;
        if (var4 >= MAX_RINTL)
            var4=0;

        pint_read = var4;

        switch(serial_flag)
        {
            case 0: /*收到起始位*/
                if (var1 == SYN)
                {
                    serial_flag = 1;
//com_send_command(0x01); //測試
                }
                else
                {
                    serial_flag = 0;
                }
                break;

            case 1:/*收到起始位*/
                if (var1 == SYN)
                {
                    serial_flag = 2;
//com_send_command(0x02); //測試
                }
                else
                {
                    serial_flag = 0;
                }
                break;

            case 2:/*收到同步位*/
                if (var1 == STX)
                {
                    serial_flag = 3;
//com_send_command(0x03);//測試
                }
                else
                {
                    serial_flag = 0;
                }
                break;

            case 3: /*收到組地址*/
                if (var1 == ADDRESS[0])
                {
                    serial_flag = 4;
                    prec_num = 1;
                    prec_buf[0] = var1;
//com_send_command(0x04); //測試
                }
                else
                {
                    serial_flag = 0;
                }
                break;

            case 4:/*收到本機地址或者廣播地址*/
                if ( (var1 == ADDRESS[1]) || (var1 == 0) )
                {
                    prec_num = 2;
                    prec_buf[1] = var1;
                    serial_flag = 5;
//com_send_command(0x05); //測試
                }
                else
                {
                    serial_flag = 0;
                }
                break;

            case 5:/*數(shù)據(jù)長度*/
                prec_num = 3;
                prec_buf[2] = var1;
                serial_lengthl = var1;
                serial_flag = 6;
//com_send_command(0x06);//測試
                break;

            case 6:
                prec_num = 4;
                prec_buf[3] = var1;
                serial_length |= var1;
                serial_length = ( (serial_length << 8) & 0xff00 ) + serial_lengthl + 3;
                serial_flag = 7;
//com_send_command(0x07);//測試
                break;

            case 7:
                prec_buf[prec_num] = var1;
                prec_num++;
                serial_length--;
                if (serial_length == 0)
                {
                    crc_data = CalCRC16_1021(prec_buf, prec_num - 2); /* 計算crc校驗和(從組地址開始到ETX )*/

                    if ( ( (crc_data & 0x00ff) == prec_buf[prec_num - 2]) && ( ( (crc_data >>8) & 0x00ff) == prec_buf[prec_num - 1]) ) /* 校驗和正確 */
                    {
                        prec_num = 1;
                        var1 = 0;

                        if ( (prec_buf[4] >= 0x31) && (prec_buf[4] <= 0x3b) ) /* 命令有效 */
                        {
                            if (prec_buf[1] != 0x00) /* 如果不是廣播地址則回應(yīng)ACK*/
com_send_command(0x49);//測試                                 msg_last_push(MSG_ACK,0);
//                                                                send_command(ACK); //測試   

                            command_decoder(); /* 如果校驗和正確,則進行命令解碼 */
                        }
                        else
                        {

send_command(NAK); //測試
                        }
                    }
                    else
                    {

send_command(NAK); //測試
                    }
                    serial_flag = 0;
                    prec_num = 1;
                }
                break;

            default:
                serial_flag = 0;
                prec_num = 1;
                break;
        }
    }
}
/* 命令解碼子程序 */
void command_decoder(void)
{
//    uint8_t i = 0;

    if (prec_buf[4] == 0x31)       /* 設(shè)置報警閾值   */
    {                  
com_send_command(0x11);//測試
        return;
    }
    else if (prec_buf[4] == 0x32)  /* 請求報警閾值 */
    {
com_send_command(0x12);//測試?
        return;
    }
    else if (prec_buf[4] == 0x33)  /* 修改當前時間 */
    {
com_send_command(0x13);//測試
        return;
    }
    else if (prec_buf[4] == 0x34)  /* 請求當前時間 */
    {
com_send_command(0x14);//測試
        return;
    }
    else if (prec_buf[4] == 0x35)  /* 請求當前數(shù)據(jù) */
    {
com_send_command(0xAA);//測試        
//__nop();
com_send_command(0x15);//測試
        return;
    }
    else if (prec_buf[4] == 0x36)  /* 請求看門狗信息*/
    {
com_send_command(0x16);//測試
        return;
    }
    else if (prec_buf[4] == 0x37)  /* 請求報警情況 */
    {
com_send_command(0x17);//測試
        return;
    }
    else if (prec_buf[4] == 0x38)  /* 配置設(shè)備地址 */
    {
        ADDRESS[0] = prec_buf[5];  /* 通訊組地址   */
        ADDRESS[1] = prec_buf[6];  /* 開發(fā)板地址   */
com_send_command(0x181);//測試
        return;
    }
    else if (prec_buf[4] == 0x39)  /* 請求設(shè)備地址 */
    {
com_send_command(0x19);//測試
        return;
    }
    else if (prec_buf[4] == 0x3a)  /* 控制模擬量輸出 */
    {
com_send_command(0x1A);//測試?
        return;
    }
    else if (prec_buf[4] == 0x3b)  /* 控制開關(guān)量輸出 */
    {
com_send_command(0x1B);//測試
        return;
    }
//                if (prec_buf[4] == 0x00)       /* 如果是廣播地址  */
//    {                  
//                                com_send_command(SYN);
//                                com_send_command(0x00);
//                                com_send_command(SYN);
//        return;
//    }
}

/* 向PC主機發(fā)送消息幀,入口參數(shù):消息類型 */
void send_command(uint8_t command)
{
    switch (command)
    {
        case ACK:
            com_send_command(SYN);
            com_send_command(SYN);
            com_send_command(ACK);
            break;

        case NAK:
            com_send_command(SYN);
            com_send_command(SYN);
            com_send_command(NAK);
            break;

        default:
            break;
    }
}

/*計算CRC校驗和使用MTT(0X1021)
參數(shù):
pBuff 為需計算CRC的緩沖區(qū)的頭指針
BufferLen 緩沖區(qū)長度(以字節(jié)計)
*/
u_short CalCRC16_1021(uint8_t x[], u_short BufferLen)
{
    u_short i;
    uint8_t  j;
    u_short crc16 = 0;
    u_short mask = 0x1021;
    uint8_t *pByteBuffer;
    uint8_t tmpbyte;
    u_short calval;

    pByteBuffer = &x[0];

    for (i = 0; i < BufferLen; i++)
    {
        tmpbyte = *pByteBuffer;
        calval = tmpbyte << 8;
        for (j = 0; j < 8; j++)
        {
            if ((crc16 ^ calval) & 0x8000)
                crc16 = (crc16 << 1) ^ mask;
            else
                crc16 <<= 1;

            calval <<= 1;
        }
        pByteBuffer++;
    }
    return crc16;
}

COMINT.h
#ifndef __COMINT_H__
#define __COMINT_H__

#include <stdio.h>
#include <pic.h>

#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000UL   //4M晶振
#endif

#define BAUDRATE        3      //定義波特率 9600  N 8 1

#define INT8U   unsigned char
#define INT16U  unsigned int
#define uint8_t   unsigned char
#define u_short  unsigned int
#define uint16_t  unsigned int

#define ZU                        0x01                 /*組地址*///通訊地址修改這兩項
#define ZHAN                0x02                 /*站地址*///通訊地址修改這兩項

#define MAX_RINTL       16   /* 串口接收緩沖區(qū)長度   */
#define SYN           0x16   /* 通訊同步位*/
#define STX           0x02   /* 通訊起始位*/
#define ETX           0x03   /* 通訊結(jié)束位*/

#define ACK           0x06
#define NAK           0x15

#define MSG_ACK          2    /* 正確應(yīng)答信息         */
#define MSG_NAK          3    /* 錯誤應(yīng)答信息         */
#define MAX_COMMAND_LEN  16   /* 串口接受命令長度     */

extern char str_test[25]  ;
extern uint8_t  pint_read;             // 串口緩沖區(qū)讀指針     */
extern uint8_t  pint_write;            // 串口緩沖區(qū)寫指針
//extern uint8_t  data  psend_int;             // 串口發(fā)送允許標志   
extern uint8_t  pint_buf[MAX_RINTL];   // 串口接收緩沖區(qū)      
extern uint8_t serial_flag;              /* 串口接收數(shù)據(jù)標志位   */

extern uint8_t  prec_buf[MAX_COMMAND_LEN];/* 命令接收緩沖區(qū) */        

/* 串口初始化*/
void Serial_port_init(void);
/* 串口發(fā)送一個字節(jié) */
void com_send_command(char Onebyte);
void Send_String(char *str);// 向PC機發(fā)送字符串
/* 串口接收數(shù)據(jù)處理 */
void com_command_receive(void);
/* 串口接收初始化 */
void buff_init(void);

///* 串口接收一字節(jié)數(shù)據(jù) */
//unsigned char UartReadChar(void); //reentrant
/*計算CRC校驗和使用MTT(0X1021)
參數(shù):
pBuff 為需計算CRC的緩沖區(qū)的頭指針
BufferLen 緩沖區(qū)長度(以字節(jié)計)
*/
u_short CalCRC16_1021(uint8_t x[], u_short BufferLen);

/* 命令解碼子程序 */
void command_decoder(void);
/* 向主機發(fā)送消息幀,入口參數(shù):消息類型 */
void send_command(uint8_t command);

#endif



                                                                                            

                                                                                
                                                                                                                                                        
                                                        
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂1 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:106187 發(fā)表于 2020-9-22 19:23 | 只看該作者
謝謝樓主和平臺共享。。。
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表