#include "delay.h"
#include "usart3.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
#include "timer.h"
#include "lcd.h"
#include "usart.h"
//串口接收緩存區
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接收緩沖,最大USART3_MAX_RECV_LEN個字節.
u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //發送緩沖,最大USART3_MAX_SEND_LEN字節
//通過判斷接收連續2個字符之間的時間差不大于10ms來決定是不是一次連續的數據.
//如果2個字符接收間隔超過10ms,則認為不是1次連續數據.也就是超過10ms沒有接收到
//任何數據,則表示此次接收完畢.
//接收到的數據狀態
//[15]:0,沒有接收到數據;1,接收到了一批數據.
//[14:0]:接收到的數據長度
vu16 USART3_RX_STA=0;
u16 i;
u16 check;
u8 uart3_len=0; //數據長度,uart3_len+1加上幀尾
u8 x=0;
u8 RxCounter1=0;
u8 RxBuffer1[20]={0};
u8 RxState = 0;
//USART1 全局中斷服務函數
//初始化IO 串口3
//pclk1:PCLK1時鐘頻率(Mhz)
//bound:波特率
void usart3_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOB時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3時鐘使能
USART_DeInit(USART3); //復位串口3
//USART3_TX PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
//USART3_RX PB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11
USART_InitStructure.USART_BaudRate = bound;//波特率一般設置為9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數據流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式
USART_Init(USART3, &USART_InitStructure); //初始化串口 3
USART_Cmd(USART3, ENABLE); //使能串口
//使能接收中斷
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//開啟中斷
//設置中斷優先級
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//搶占優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器
TIM7_Int_Init(99,7199); //10ms中斷
USART3_RX_STA=0; //清零
TIM_Cmd(TIM7,DISABLE); //關閉定時器7
}
unsigned short CRC16_XMODEM(unsigned char *puchMsg, unsigned int usDataLen)
{
unsigned short wCRCin = 0x0000;
unsigned short wCPoly= 0x1021;
unsigned char wChar = 0;
while (usDataLen--)
{
wChar = *(puchMsg++);//4,1 3,2 3,3, 1,4 1,5
wCRCin ^=(wChar << 8);
for( i = 0; i< 8; i++)
{
if(wCRCin & 0x8000)
{
wCRCin =(wCRCin << 1) ^ wCPoly;
}
else
{
wCRCin = wCRCin << 1;
}
}
}
return(wCRCin);
}
void USART3_IRQHandler(void)
{
if( USART_GetITStatus(USART3,USART_IT_RXNE)!=RESET) //接收中斷
{
USART_ClearITPendingBit(USART3,USART_IT_RXNE); //清除中斷標志
RxBuffer1[RxCounter1++] = USART_ReceiveData(USART3);
}
if(RxBuffer1[RxCounter1-1]==13) //0x0D
{
uart3_len=RxCounter1-1;
check=CRC16_XMODEM(&RxBuffer1[RxCounter1],uart3_len+1); //校驗和(crc)
if(((check&0x00ff)==RxBuffer1[uart3_len+1])&&(((check>>8)&0x00ff)==RxBuffer1[uart3_len+1]))
{
RxState=1;
}
}
if(USART_GetFlagStatus(USART3,USART_FLAG_ORE) == SET) //判斷中斷是否溢出
{
USART_ClearFlag(USART3,USART_FLAG_ORE);
USART_ReceiveData(USART3);
}
if(RxState)
{
for(x=0;x<uart3_len+1;x++)
{USART_SendData(USART1,RxBuffer1[x]);
delay_ms(10);}
RxState=0;
RxCounter1=0;
}
}
//串口3,printf 函數
//確保一次發送數據不超過USART3_MAX_SEND_LEN字節
//void u3_printf(char* fmt,...)
//{
// u16 i,j;
// va_list ap;
// va_start(ap,fmt);
// vsprintf((char*)USART3_TX_BUF,fmt,ap);
// va_end(ap);
// i=strlen((const char*)USART3_TX_BUF); //此次發送數據的長度
// for(j=0;j<i;j++) //循環發送數據
// {
// while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循環發送,直到發送完畢
// USART_SendData(USART3,USART3_TX_BUF[j]);
// }
//}
掃描過后,模塊的串口通訊參數:波特率 9600bps,無校驗,8 位數據位,1 位停止位,無流控。
改為串口后,所有的數據都由串口輸出,也可以直接發送命令控制模塊
對模塊的標志位進行讀操作:
發送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00(2 bytes)
Types :0x07(1 byte)
Lens :0x01(1 byte)
Address :0x0000~0x00FF(2 bytes),表示要讀取的標志位的起始地址。
Datas :0x00~0xFF(1 byte),表示要連續讀取的標志位的字節數,0x00 表示 256 個字節。
CRC :CRC_CCITT 校驗值(2 bytes)。計算的范圍:Types、Lens、Address、Datas。
計算的方法為 CRC_CCITT,特征多項式:X16+X12+X5+1,多項式系數為 0x1021,
初始值為全 0,對于單個字節來說最高位先計算,不需要取反直接輸出。
注:當用戶不需要 CRC 校驗功能時,可在 CRC 字節處填寫 0xAB 0xCD,免校驗。
接收到數據格式:
1:如果模塊成功數據并且成功返回
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types :0x00(讀成功)
Lens :表示上傳的 Datas 的字節個數,0x00 表示 256 個
Datas :0x00~0xFF,表示讀上來的數據
CRC : CRC_CCITT 校 驗 值 。 計算的范圍:Types、Lens、Datas。計算的方法為 CRC_CCITT,特征多項式:X16+X12+X5+1,多項式系數為 0x1021,初
始值為全 0,對于單個字節來說最高位先計算,不需要取反直接輸出。
注:當用戶不需要 CRC 校驗功能時,可在 CRC 字節處填寫 0xAB 0xCD,免校驗。
2: 下發 CRC 校驗失敗
無回應命令
3:未知命令應答
無回應命令
示例:(供參考)
CRC C 參考代碼:
unsigned int crc_cal_by_bit(unsigned char* ptr, unsigned int len)
{
unsigned int crc = 0;
while(len-- != 0)
{
for(unsigned char i = 0x80; i != 0; i /= 2)
{
crc *= 2;
if((crc&0x10000) !=0) //上一位 CRC 乘 2 后,若首位是 1,則除以 0x11021
crc ^= 0x11021;
if((*ptr&i) != 0) //如果本位是 1,那么 CRC = 上一位的 CRC + 本位/CRC_CCITT
crc ^= 0x1021;
}
ptr++;
}
return crc;
}
注:當用戶不需要 CRC 校驗功能時,可在 CRC 字節處填寫 0xAB 0xCD,免校驗。
示例:
對標志位中地址為 0x000A 的 1 個地址進行讀操作
1:讀成功并返回數據,返回的數據為 0x3E
輸入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01 0xEE 0x8A
返回:0x02 0x00 0x00 0x01 0x3E 0xE4 0xAC
2:下發的 CRC 錯誤
輸入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01 0x11 0x22
返回:無
3:當發送的指令長度不夠或發送 0x7e 0x00 后等待時間超過 400ms 時,當成未知命令處理
輸入:0x7E 0x00 0x07 0x01 0x00 0x0A 0x01
返回:無
對模塊標志位進行寫操作:
發送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00(2 bytes)
Types :0x08(1 byte)
Lens :0x00~0xFF(1 byte),表示該命令中 Datas 字段的字節數,同時也表示要進行連續
寫操作的次數,而 0x00 表示有 256 個字節
Address :0x0000~0xFFFF(2 bytes),表示要寫入的標志位的起始地址
Datas :0x00~0xFF(1~256 bytes),表示寫入標志位的數據
CRC :CRC_CCITT 校驗值(2 bytes)。計算的范圍:Types、Lens、Address、Datas
注:當用戶不需要 CRC 校驗功能時,可在 CRC 字節處填寫 0xAB 0xCD,免校驗。
返回數據格式:
1:寫標志位成功
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types :0x00(寫成功)
Lens :0x01
Datas :0x00
CRC :CRC_CCITT
2:下發 CRC 校驗失敗
無回應命令
3:未知命令應答
無回應命令
示例:
向地址為 0x000A 的標志位寫入 0x3E
1: 設置成功
輸入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E 0x4C 0xCF
返回:0x02 0x00 0x00 0x01 0x00 0x33 0x31
2: 下發的 CRC 錯誤
輸入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E 0x11 0x22
返回:無
3: 當發送的指令長度不夠或發送 0x7e 0x00 后等待時間超過 400ms 時,當成未知命令處理
輸入:0x7E 0x00 0x08 0x01 0x00 0x0A 0x3E
返回:無
標志位保存到 EEPROM 指令
若要將設備標志位的內容保存到外掛的 EERPOM 中則需要發送保存命令。
數據發送命令格式:
{Head1} {Types} {Lens} {Address} {Datas} {CRC}
Head1 :0x7E 0x00
Types :0x09
Lens :0x01
Address :0x0000
Datas :0x00
CRC :CRC_CCITT 校驗值(0xDE 0xC8)
接收數據格式:
1:保存成功
{Head2} {Types} {Lens} {Datas} {CRC}
Head2 :0x02 0x00
Types :0x00(寫成功)
Lens :0x01
Datas :0x00
CRC :CRC_CCITT 校驗值(0x33 0x31)
2:下發 CRC 校驗失敗
無回應命令
3:未知命令應答
無回應命令
部分串口命令示例:
1:觸發掃描串口指令為:7E 00 08 01 00 02 01 AB CD;識讀模塊收到觸發指令后,會先輸出七個字節的回應信息并同步啟動掃描(回應信息內容:02 00 00 01 00 33 31)
2:設置模塊為命令觸發模式,照明燈常亮,普通瞄準,啟動靜音,開啟解碼成功LED提示
發送格式:7E 00 08 01 00 00 99 AB CD
接收成功后返回: 02 00 01 00 33 31
3:設置模塊為感應模式,照明燈關閉,瞄準常亮,關閉靜音,關閉解碼成功LED提示
發送格式:7E 00 08 01 00 00 63 AB CD
接收成功后返回: 02 00 01 00 33 31
4:從標志位0X0002中讀取數據,判斷是否輸出解碼狀態提示符
發送格式:7E 00 07 01 00 02 01 AB CD
接收成功后返回;02 00 00 01 40 AB CD
Keil代碼等資料下載:
GM65.7z
(1.34 MB, 下載次數: 57)
2022-4-28 18:09 上傳
點擊文件名下載附件
|