main.c /****************************************************************************/ /* */ /* Copyright (c) 2016, 老馬工作室 */ /* All rights reserved. */ /* */ /* Email:pcwebmaster@163.com */ /****************************************************************************/ /****************************************************************************/ /* 文 件 名:comint.c */ /* 版 本:Version 1.0 */ /* 描 述:串行口中斷帶通訊協議測試 */ /* 主控芯片:PIC16F1937 */ /* 晶振頻率:4MHz */ /* 作 者:pcwebmaster(北極狼) */ /* 函 數: */ /* system_init */ /* com_send_command */ /* com_command_receive */ /* CalCRC16_1021 */ /* command_decoder */ /* send_command */ /* 測 試: 發送:16 16 02 01 02 01 00 35 03 94 BD接收:49 AA 15 */ /* 測試現象: */ /* 歷史記錄: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 //內部4MHz //*******************************************************************// // 系統初始化 //*******************************************************************// void System_Init(void) { OSCCON = 0b01101000; //內部4MHz OSCTUNE= 0b00000000; //出廠校準 ADCON1 = 0b10110000; //內部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; //關電平變化中斷 IOCBN = 0b00000000; TRISD = 0b00000000; //PORTD輸出 ANSELD = 0b00000000; //數字 I/O TRISC = 0b10011000; //串口 I2C TRISE = 0b00000000; //PORTE輸出 ANSELE = 0b00000000; //數字 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(); //系統初始化 CLRWDT(); //WDT看門狗 TMR0_Init(); //TMR0初始化 Serial_port_init(); //UART初始化 PEIE = 1; //外設中斷允許 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 */ /* 描 述:串行口中斷帶通訊協議測試 */ /* 主控芯片:PIC16F1937 */ /* 晶振頻率:4MHz */ /* 作 者:pcwebmaster(北極狼) */ /* 函 數: */ /* system_init */ /* com_send_command */ /* com_command_receive */ /* CalCRC16_1021 */ /* command_decoder */ /* send_command */ /* 測 試: 發送:16 16 02 01 02 01 00 35 03 94 BD接收:49 AA 15 */ /* 測試現象: */ /* 歷史記錄:20016.02.19測試通過 */ /* 北極狼 20016-02-19 Creat Inital version. (Version 1.0) */ /****************************************************************************/ #include <pic.h> #include "comint.h" uint8_t pint_buf[MAX_RINTL]; /* 串口接收緩沖區 */ uint8_t pint_read; /* 串口緩沖區讀指針 */ uint8_t pint_write; /* 串口緩沖區寫指針 */ //uint8_t psend_int; /* 串口發送允許標志 */ uint8_t serial_flag = 0; /* 串口接收數據標志位 */ uint8_t prec_buf[MAX_COMMAND_LEN]; /* 命令接收緩沖區 */ uint8_t prec_num; /* 命令接收緩沖區字節數 */ uint8_t serial_lengthl = 0; /* 消息命令長度低8位 */ uint16_t serial_length = 0; /* 消息命令長度16位 */ uint8_t ADDRESS[2]={ZU,ZHAN}; /* byte0:通訊組地址, byte1:開發板地址 */ //----------------------------------------------------------------- // 串口初始化 //----------------------------------------------------------------- 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 } //----------------------------------------------------------------- // 串口發送一個字節 //----------------------------------------------------------------- void com_send_command(char Onebyte) { TXREG = Onebyte; while(TRMT); __delay_ms(1);//4M晶體最少需要1MS延時,?? } //------------------------------------------------------------------ // (串口接收)中斷程序(緩沖滿時數據前移) //------------------------------------------------------------------ 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; //讀取數據 temp = pint_write + 1; /* 判斷是否可以寫入 */ if (temp == MAX_RINTL) { temp=0; } if (temp != pint_read) { pint_buf[pint_write] = temp1; /* 讀取數據 */ pint_write = temp; } } } void buff_init(void) { uint8_t loop; loop = RCREG; /* 清串口緩沖區 */ for (loop=0; loop<MAX_RINTL; loop++) { pint_buf[loop] = 0; } } ////////////////////////////以上需要修改移植,以下直接移植并添加代碼///////////////////////////////////////////// //------------------------------------------------------------------ // 向PC機發送字符串 //------------------------------------------------------------------ void Send_String(char *str) { while(*str) //檢測str是否有有效 { com_send_command(*str++); } } /* 串口接收數據處理 */ 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:/*數據長度*/ 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) /* 如果不是廣播地址則回應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) /* 設置報警閾值 */ { 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) /* 請求當前數據 */ { 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) /* 配置設備地址 */ { ADDRESS[0] = prec_buf[5]; /* 通訊組地址 */ ADDRESS[1] = prec_buf[6]; /* 開發板地址 */ com_send_command(0x181);//測試 return; } else if (prec_buf[4] == 0x39) /* 請求設備地址 */ { com_send_command(0x19);//測試 return; } else if (prec_buf[4] == 0x3a) /* 控制模擬量輸出 */ { com_send_command(0x1A);//測試? return; } else if (prec_buf[4] == 0x3b) /* 控制開關量輸出 */ { com_send_command(0x1B);//測試 return; } // if (prec_buf[4] == 0x00) /* 如果是廣播地址 */ // { // com_send_command(SYN); // com_send_command(0x00); // com_send_command(SYN); // return; // } } /* 向PC主機發送消息幀,入口參數:消息類型 */ 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) 參數: pBuff 為需計算CRC的緩沖區的頭指針 BufferLen 緩沖區長度(以字節計) */ 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 /* 串口接收緩沖區長度 */ #define SYN 0x16 /* 通訊同步位*/ #define STX 0x02 /* 通訊起始位*/ #define ETX 0x03 /* 通訊結束位*/ #define ACK 0x06 #define NAK 0x15 #define MSG_ACK 2 /* 正確應答信息 */ #define MSG_NAK 3 /* 錯誤應答信息 */ #define MAX_COMMAND_LEN 16 /* 串口接受命令長度 */ extern char str_test[25] ; extern uint8_t pint_read; // 串口緩沖區讀指針 */ extern uint8_t pint_write; // 串口緩沖區寫指針 //extern uint8_t data psend_int; // 串口發送允許標志 extern uint8_t pint_buf[MAX_RINTL]; // 串口接收緩沖區 extern uint8_t serial_flag; /* 串口接收數據標志位 */ extern uint8_t prec_buf[MAX_COMMAND_LEN];/* 命令接收緩沖區 */ /* 串口初始化*/ void Serial_port_init(void); /* 串口發送一個字節 */ void com_send_command(char Onebyte); void Send_String(char *str);// 向PC機發送字符串 /* 串口接收數據處理 */ void com_command_receive(void); /* 串口接收初始化 */ void buff_init(void); ///* 串口接收一字節數據 */ //unsigned char UartReadChar(void); //reentrant /*計算CRC校驗和使用MTT(0X1021) 參數: pBuff 為需計算CRC的緩沖區的頭指針 BufferLen 緩沖區長度(以字節計) */ u_short CalCRC16_1021(uint8_t x[], u_short BufferLen); /* 命令解碼子程序 */ void command_decoder(void); /* 向主機發送消息幀,入口參數:消息類型 */ void send_command(uint8_t command); #endif |
歡迎光臨 (http://www.raoushi.com/bbs/) | Powered by Discuz! X3.1 |