NUC140之串列埠UART
阿新 • • 發佈:2019-01-12
UART可以說是序列通訊用的最多的協議,相對其他協議也比較簡單,一般只要設定好位元率,資料位,停止位和校驗位即可。下面來看程式。
#include "UART.h" #include <stdio.h> volatile static uint8_t Rx_UART[20] = {0}; //串列埠儲存接收資料陣列,加static作為靜態全域性變數僅能在本檔案內部使用 volatile static uint8_t Rx_UART_counter = 0; //串列埠儲存接收資料陣列計數器 volatile static uint8_t UART_one_frame_end; //串列埠一幀資料傳輸結束標誌 volatile static uint8_t return_OK_flag = 0; //判斷是否是設定命令標誌 volatile static uint8_t verify_data[20] = {0}; //寄存用於校驗的值的陣列 void UART_callback (uint32_t tempdata); /************************************************** *函式名: send_to_UART * *功能: keil庫函式傳送UART * *出口引數:無 * *入口引數:無 * *************************************************/ void send_to_UART(const uint8_t *src,uint8_t len) { uint8_t i = 0 ; printf("\n"); for(i=0;i<len;i++) { printf("%.2X",src[i]); } printf("\r"); } /************************************************** *函式名: uint8_t check_ASCII_table * *功能: ASCII碼查表函式 * *出口引數:無 * *入口引數:無 * *************************************************/ void initialize_UART_clock (void) { DrvSYS_UnlockProtectedReg (); //解鎖受保護的系統暫存器 DrvSYS_SetOscCtrl (E_SYS_XTL12M, 1); DrvSYS_SelectIPClockSource (E_SYS_UART_CLKSRC, 0x00); //設定UART時鐘源為外部12MHz晶振 DrvSYS_SetIPClock (E_SYS_UART0_CLK, 1); //使能串列埠0的時鐘 DrvSYS_LockProtectedReg (); //對系統暫存器上鎖 } /************************************************** *函式名: initialize_UART * *功能: 初始化串列埠 * *出口引數:無 * *入口引數:無 * *************************************************/ void initialize_UART (void) { STR_UART_T sParam; sParam.u32BaudRate = 9600; //波特率9600 sParam.u8cDataBits = DRVUART_DATABITS_8; //資料位8位 sParam.u8cStopBits = DRVUART_STOPBITS_1; //停止位1bit sParam.u8cParity = DRVUART_PARITY_NONE; //無校驗 sParam.u8cRxTriggerLevel = DRVUART_FIFO_1BYTES; //串列埠中斷觸發級別1個位元組 DrvUART_Open (UART_PORT0, &sParam); //埠0初始化 delay (100); //延遲使時鐘穩定 DrvUART_EnableInt(UART_PORT0, //使能串列埠0中斷 DRVUART_RDAINT, //接收到資料進入中斷 UART_callback); //中斷回撥函式 } /************************************************** *函式名: UART_callback * *功能: 串列埠接收函式 * *出口引數:無 * *入口引數:有,暫無用 * *************************************************/ void UART_callback (uint32_t tempdata) { uint8_t temp_UART[1] = {0}; //串列埠接收臨時儲存變數陣列 volatile static uint8_t start_flag = 0; //串列埠通訊開始標誌 DrvUART_Read(UART_PORT0, //讀取埠0的資料 temp_UART, //儲存於該陣列中 1); //讀取位元組數為1 if (start_flag != 0) //通訊開始後才進入 { if (temp_UART[0] == 13) //如果收到結束標誌位(ASCII碼13對應CR,結束標誌位) { UART_one_frame_end = 1; //表示已經接收到一幀資料,要進行判斷 start_flag = 0; //清零等待下一幀的開始 } else { Rx_UART[Rx_UART_counter] = temp_UART[0]; //將接收到的位元組挨個儲存起來 Rx_UART_counter++; } } if (temp_UART[0] == 10) //如果收到起始標誌位(ASCII碼10對應LF,起始標誌位) { start_flag = 1; //串列埠通訊開始 } if (UART_one_frame_end == 1) //串列埠接收到了命令 { if (UART_Rx_verify()) //如果校驗結果一致 { UART_Rx_solve(); //接收資料處理函式 if(return_OK_flag == 1) { UART_Tx(RX_OK_COMMMAND); //回傳收到的資料與檢驗結果一致(以‘B’開頭的設定命令要返回,以'A'開頭的查詢命令無需返回) return_OK_flag = 0; } } else { UART_Tx(RX_ERROR_COMMAND); //回傳收到的資料與檢驗結果不一致 } } } /************************************************** *函式名: UART_Rx_verify * *功能: 串列埠接收資料校驗函式 * *出口引數:為1:接收資料與校驗結果一致 * 為0:接收資料與校驗結果不一致 * *入口引數:無 * ***************************************************/ uint8_t UART_Rx_verify (void) { uint8_t verify_value = 0; uint8_t verify_value_Rx = 0; uint8_t i; uint8_t temp_data[20] = {0}; check_ASCII_table((uint8_t *)Rx_UART, (uint8_t *)temp_data, Rx_UART_counter); //收到校驗碼後先將ASCII碼轉譯為16進位制數值後再校驗 combine((uint8_t *)temp_data, (uint8_t *)verify_data, Rx_UART_counter); //轉譯後合併 for (i=0; i<(Rx_UART_counter/2-1); i++) //和校驗,溢位不管,由於收到的最後兩個資料是校驗值,所以不計入該次計算中 { verify_value *= 3; verify_value += verify_data[i]; } verify_value_Rx = verify_data[Rx_UART_counter/2-1]; //讀取傳送回來的校驗值 if ((verify_value == verify_value_Rx)&&((Rx_UART_counter%2)==0)) //收到的一定是偶數個位元組 { Rx_UART_counter = 0; //計數器清零 return (1); //返回接收資料與校驗結果一致,開始判斷 } else { Rx_UART_counter = 0; //計數器清零 UART_one_frame_end = 0; //由於不必判斷,清除一幀接收完成標誌,可以接收下一幀資料 return (0); //返回接收資料與校驗結果不一致,不必判斷 } } /************************************************** *函式名: UART_Rx_solve * *功能: 串列埠接收資料處理函式 * *出口引數:無 * *入口引數:無 * *************************************************/ void UART_Rx_solve(void) { if (Rx_UART[0] == 'B') { return_OK_flag = 1; } else { return_OK_flag = 0; } if (verify_data[0] == 0xb1) { power_value = CHECK_BCD_TABLE(verify_data[2]); if (power_value > 50) { power_value = 50; } else if (power_value < 10) { power_value = 10; } SPI_U28_write(power_setup_table[power_value]); at24c32_write(DEVICE_ADDRESS, POWER_VALUE_HIGH_ADDRESS, POWER_VALUE_LOW_ADDRESS, power_value); SPI_U27_write(modulation_setup_table[power_value][modulation_value]); } else if (verify_data[0] == 0xb2) { modulation_value = CHECK_BCD_TABLE(verify_data[2]); if (modulation_value > 99) { modulation_value = 99; } else if (modulation_value < 30) { modulation_value = 30; } SPI_U27_write(modulation_setup_table[power_value][modulation_value]); at24c32_write(DEVICE_ADDRESS, MODULATION_VALUE_HIGH_ADDRESS, MODULATION_VALUE_LOW_ADDRESS, modulation_value); } else if (verify_data[0] == 0xb3) { if (verify_data[2] == 1) { radio_main = 1; } else { radio_main = 0; } at24c32_write(DEVICE_ADDRESS, RADIO_MAIN_HIGH_ADDRESS, RADIO_MAIN_LOW_ADDRESS, radio_main); } else if (verify_data[0] == 0xb4) { if (verify_data[2] == 0) { enable_PTT_limit = 0; at24c32_write(DEVICE_ADDRESS, ENABLE_PTT_LIMIT_HIGH_ADDRESS, ENABLE_PTT_LIMIT_LOW_ADDRESS, 0); //存入新的是否使能發定時功能預設值 } else { enable_PTT_limit = 1; at24c32_write(DEVICE_ADDRESS, ENABLE_PTT_LIMIT_HIGH_ADDRESS, ENABLE_PTT_LIMIT_LOW_ADDRESS, 1); //存入新的是否使能發定時功能預設值 PTT_limit_time = verify_data[2] * 60; //發定時時間資料是按檔位發過來的 if (PTT_limit_time > 300) { PTT_limit_time = 300; } DrvTIMER_ClearTimerEvent(E_TMR0,0); setup_ptt_limit_time (PTT_limit_time); at24c32_write(DEVICE_ADDRESS, PTT_LIMIT_TIME_HIGH_ADDRESS, PTT_LIMIT_TIME_LOW_ADDRESS, (Rx_UART[2] - 48)); //存入新的發定時時間預設值 } } else if (verify_data[0] == 0xb5) { if (verify_data[2] == 0) { enable_error = 0; at24c32_write(DEVICE_ADDRESS, ENABLE_ERROR_HIGH_ADDRESS, ENABLE_ERROR_LOW_ADDRESS, 0); //存入新的是否使能報錯關二次預設值 } else { enable_error = 1; at24c32_write(DEVICE_ADDRESS, ENABLE_ERROR_HIGH_ADDRESS, ENABLE_ERROR_LOW_ADDRESS, 1); //存入新的是否使能報錯關二次預設值 } } else if (verify_data[0] == 0xb6) { carrier_frequency = CHECK_BCD_TABLE(verify_data[2]) * 10000 + CHECK_BCD_TABLE(verify_data[3]) * 100 + CHECK_BCD_TABLE(verify_data[4]);/ if (carrier_frequency < 118000) { carrier_frequency = 118000; } if (carrier_frequency > 144000) { carrier_frequency = 144000; } if ((carrier_frequency%25)==0) { channel_space = 1; DrvGPIO_ClrBit (E_GPC, 5); //PC.5置0 } else { channel_space = 0; DrvGPIO_SetBit (E_GPC, 5); //PC.5置1 } carrier_frequency /= 1000; at24c32_write(DEVICE_ADDRESS, CHANNEL_SPACE_HIGH_ADDRESS, CHANNEL_SPACE_LOW_ADDRESS, channel_space);//存入通道間隔新值 at24c32_write(DEVICE_ADDRESS, FREQUENCY_HIGH_ADDRESS, FREQUENCY_LOW_ADDRESS, carrier_frequency);//存入電臺地址新值 } else if (verify_data[0] == 0xb7) { if (verify_data[2] == 0) { Rx_SQ(0); } else { Rx_SQ(1); } } else if (verify_data[0] == 0xb8) { if (verify_data[2] == 0) { status_register2.status_sample.PC_off = 1; //置位狀態標誌 } else { status_register2.status_sample.PC_off = 0; //置位狀態標誌 } } else if (verify_data[0] == 0xb9) { error_register1.error_sample_all = 0; temperature_error_counter = 0; supply_28V_error_counter = 0; DISF_solve_counter = 0; DIRR_solve_counter = 0; else if (verify_data[0] == 0xba) { if (verify_data[2] == 0) { PTT_enable = 0; //禁發PTT } else { PTT_enable = 1; //允許發PTT } } else if (verify_data[0] == 0xa1) { UART_Tx (DISF_DISR_DISM_VALUE_COMMAND); } else if (verify_data[0] == 0xa2) { UART_Tx (READ_ERROR_COMMAND); } else if (verify_data[0] == 0xa3) { UART_Tx (READ_TEMPERATURE_COMMAND); } else if (verify_data[0] == 0xa6) { UART_Tx (RECEIVER_AGC_COMMMAND); } else if (verify_data[0] == 0xa7) { UART_Tx (READ_ALL_STATUS_COMMMAND); } UART_one_frame_end = 0; //清除一幀接收完成標誌,可以接收下一幀資料 } /************************************************** *函式名: UART_Tx * *功能: 串列埠傳送函式 * *出口引數:無 * *入口引數:傳送命令型別 * *************************************************/ void UART_Tx (uint8_t command) { uint8_t temp_UART[1] = {0}; //串列埠傳送臨時儲存變數陣列 uint8_t Tx_UART[20] = {0}; //串列埠傳送儲存變數陣列 uint8_t temp_data[20] = {0}; uint8_t temp_data_verify[20] = {0}; uint8_t Tx_UART_counter = 0; //串列埠傳送儲存變數陣列計數器 uint8_t verify_value = 0; //校驗值 uint8_t verify_value_first; //校驗值第一位 uint8_t verify_value_second; //校驗值第二位 uint8_t i; uint8_t j; Tx_UART[0] = 10; //無論哪一條命令一定先發起始標誌'LF' ASCII對應10 Tx_UART[1] = 'A'; //無論哪一條命令命令格式第一個都是字元'A' //這兩句放前面可以減少過多的重複程式碼 if (command == DISF_DISR_DISM_VALUE_COMMAND) { Tx_UART[2] = '1'; Tx_UART[3] = '0'; //資料長度為3, 分兩個位元組表示 Tx_UART[4] = '3'; Tx_UART[5] = DISF_value / 10 + '0'; //加上'0',即轉換成字元型,看ASCII碼錶就明白了(十位不可能超過9,沒有大於160的資料) Tx_UART[6] = DISF_value % 10 + '0'; Tx_UART[7] = DISR_value / 10 + '0'; Tx_UART[8] = DISR_value % 10 + '0'; Tx_UART[9] = DISM_value / 10 + '0'; Tx_UART[10] = DISM_value % 10 + '0'; Tx_UART_counter = 10; } else if (command == READ_ERROR_COMMAND) //如果是要讀取總的錯誤訊號 { Tx_UART[2] = '2'; //傳送總的錯誤訊號 Tx_UART[3] = '0'; //資料長度為2 Tx_UART[4] = '2'; Tx_UART[5] = (error_register1.error_sample_all & 0xf0)>>4; //總的錯誤訊號暫存器1高4位 NUMBER_TO_BCD(Tx_UART[5]); Tx_UART[6] = error_register1.error_sample_all & 0x0f; //總的錯誤訊號暫存器1低4位 NUMBER_TO_BCD(Tx_UART[6]); Tx_UART[7] = (status_register2.status_sample_all & 0xf0)>>4;//總的錯誤訊號暫存器2高4位 NUMBER_TO_BCD(Tx_UART[7]); Tx_UART[8] = status_register2.status_sample_all & 0x0f; //總的錯誤訊號暫存器2低4位 NUMBER_TO_BCD(Tx_UART[8]); Tx_UART_counter = 8; } else if (command == READ_TEMPERATURE_COMMAND) //如果是要讀取溫度的命令 { Tx_UART[2] = '3'; //傳送溫度值 Tx_UART[3] = '0'; //資料長度為1 Tx_UART[4] = '1'; Tx_UART[5] = temperature_value / 10 + '0'; //取溫度值的十位值 Tx_UART[6] = temperature_value % 10 + '0'; //取溫度值的個位值 Tx_UART_counter = 6; } else if (command == RX_ERROR_COMMAND) //如果是要傳送接收到的資料與校驗碼不一致 { Tx_UART[2] = '4'; Tx_UART[3] = '0'; //資料長度為0 Tx_UART[4] = '0'; Tx_UART_counter = 4; } else if (command == RX_OK_COMMMAND) //如果是要傳送接收到的資料與校驗碼一致 { Tx_UART[2] = '5'; Tx_UART[3] = '0'; //資料長度為0 Tx_UART[4] = '0'; Tx_UART_counter = 4; } else if (command == RECEIVER_AGC_COMMMAND) { Tx_UART[2] = '6'; Tx_UART[3] = '0'; //資料長度為1 Tx_UART[4] = '1'; Tx_UART[5] = '0'; Tx_UART[6] = Rx_AGC() + '0'; Tx_UART_counter = 6; } else if (command == READ_ALL_STATUS_COMMMAND) { Tx_UART[2] = '7'; Tx_UART[3] = '0'; //資料長度為 Tx_UART[4] = '4'; Tx_UART[5] = (error_register1.error_sample_all & 0xf0)>>4; NUMBER_TO_BCD(Tx_UART[5]); Tx_UART[6] = error_register1.error_sample_all & 0x0f; NUMBER_TO_BCD(Tx_UART[6]); Tx_UART[7] = (status_register2.status_sample_all & 0xf0)>>4; NUMBER_TO_BCD(Tx_UART[7]); Tx_UART[8] = status_register2.status_sample_all & 0x0f; NUMBER_TO_BCD(Tx_UART[8]); Tx_UART[9] = temperature_value / 10 + '0'; Tx_UART[10] = temperature_value % 10 + '0'; Tx_UART[11] = '0'; Tx_UART[12] = Rx_AGC() + '0'; Tx_UART_counter = 12; } check_ASCII_table((uint8_t *)(Tx_UART+1), (uint8_t *)temp_data, Tx_UART_counter); //收到校驗碼後先將ASCII碼轉譯為16進位制數值後再校驗 combine((uint8_t *)temp_data, (uint8_t *)temp_data_verify, Tx_UART_counter); for (i=0; i<(Tx_UART_counter/2); i++) //計算校驗值,溢位不管,注意條件是<= { verify_value *= 3; verify_value += temp_data_verify[i]; //第0個元素是起始標誌,不校驗 } verify_value_first = verify_value / 16; //取校驗值的十位數,按16進位制 verify_value_second = verify_value % 16; //取校驗值的個位數,按16進位制 NUMBER_TO_BCD(verify_value_first); NUMBER_TO_BCD(verify_value_second); Tx_UART_counter += 2; //加2準備儲存校驗值,校驗值佔2位 Tx_UART[Tx_UART_counter - 1] = verify_value_first; //儲存校驗值第一位(十位) Tx_UART[Tx_UART_counter] = verify_value_second; //儲存校驗值第二位(個位) Tx_UART_counter += 1; //加1準備儲存結束標誌 Tx_UART[Tx_UART_counter] = 13; //儲存結束標誌'CR'對應ASCII碼13 for (j=0; j<=Tx_UART_counter; j++) { temp_UART[0] = Tx_UART[j]; DrvUART_Write(UART_PORT0, //UART埠0 (uint8_t *)temp_UART, //要傳送的資料儲存陣列地址 1); //傳送位元組數 } } 標頭檔案如下 #ifndef UART_h #define UART_h #include "stdint.h" #include "DrvUART.h" #include "SPI_U27_U28.h" #include "I2C_remote.h" #include "at24c32.h" #include "timer.h" #include "delay.h" #include "common_functions.h" #include "I2C_remote.h" #define DISF_DISR_DISM_VALUE_COMMAND 0x01 #define READ_ERROR_COMMAND 0x02 //讀取總的錯誤訊號命令 #define READ_TEMPERATURE_COMMAND 0x03 //讀取溫度狀態命令 #define RX_ERROR_COMMAND 0x04 //串列埠接收資料與校驗值不一致 #define RX_OK_COMMMAND 0x05 //串列埠接收資料與校驗值一致 #define RECEIVER_AGC_COMMMAND 0x06 #define READ_ALL_STATUS_COMMMAND 0x07 extern void initialize_UART_clock (void) ; //初始化串列埠時鐘 extern void initialize_UART (void); //初始化UART extern void UART_Tx (uint8_t command); //給前面板傳送狀態,引數對應傳送的狀態型別 extern uint8_t UART_Rx_verify (void); //串列埠接收到資料校驗函式 extern void UART_Rx_solve(void); //串列埠接收資料處理函式 #endif