U盤數(shù)據(jù)采集系統(tǒng)軟件篇一(串口和矩陣鍵盤模塊)
文 | 嵌Sir
硬件設(shè)計完成,下面就要進行軟件開發(fā)了,本篇主要介紹串口模塊、按鍵模塊的初始化及功能測試。
程序開發(fā)前我習慣查看原理圖把所有外設(shè)對應(yīng)的管腳全部列出來,方便后續(xù)開發(fā)時查看。
01
串口模塊
串口管腳配置如下:
查看芯片規(guī)格書可知 PA9和PA10的默認功能為串口1,PD8和PD9需要重定義為串口3使用。
管腳定義:
本文使用中斷方式接收和發(fā)送,串口和串口中斷初始化代碼如下:
GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure; //UART1 管腳配置:時鐘、模式 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Pin = UART1_RXD_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = UART1_RXD_GPIO_MODE; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(UART1_RXD_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = UART1_TXD_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = UART1_TXD_GPIO_MODE; GPIO_Init(UART1_TXD_GPIO_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;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(USART1, &USART_InitStructure); //配置nvic向量表NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Enable the USARTy Interrupt */NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); /* Enable USART1 Receive and Transmit interrupts */USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);USART_ITConfig(USART1, USART_IT_TXE, DISABLE); //一開始就是要關(guān)閉 /* Enable USART */USART_Cmd(USART1, ENABLE); gb_needDealUart1Data = 0;uart1DelayTimer = 0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE);//UART3 管腳配置:時鐘、模式 GPIO_InitStructure.GPIO_Pin = UART3_RXD_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = UART3_RXD_GPIO_MODE; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(UART3_RXD_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = UART3_TXD_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = UART3_TXD_GPIO_MODE; GPIO_Init(UART3_TXD_GPIO_PORT, &GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200;USART_InitStructure.USART_WordLength = USART_WordLength_8b;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); //配置nvic向量表NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* Enable the USARTy Interrupt */NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); /* Enable USART3 Receive and Transmit interrupts */USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);USART_ITConfig(USART3, USART_IT_TXE, DISABLE); //一開始就是要關(guān)閉 /* Enable USART */USART_Cmd(USART3, ENABLE); gb_needDealUart3Data = 0;
初始化的時候別忘記串口3的remap。
GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE);
串口收發(fā)中斷處理,以串口3為例:
void USART3_IRQHandler(void){ u8 d; if (USART_GetFlagStatus(USART3, USART_FLAG_RXNE)) { /* Read one byte from the receive data register */ d = USART_ReceiveData(USART3); uart3infifo_DataIn(d); uart3DelayTimer = UART3_DATA_DELAY; gb_needDealUart3Data = 0; } else if (USART_GetFlagStatus(USART3, USART_FLAG_TXE)) { if (uart3outfifo_count > 0) { /* Write one b yte to the transmit data register */ USART_SendData(USART3, uart3outfifo_DataOut()); //順便清除flag_TXE } else { /* Disable the USARTy Transmit interrupt */ USART_ITConfig(USART3, USART_IT_TXE, DISABLE); //實際上,發(fā)送為空的標志還在,只是關(guān)閉中斷 } }}
串口中斷中收到數(shù)據(jù)先進FIFO,等一個數(shù)據(jù)包接收完后進入處理。需要發(fā)送數(shù)據(jù),把數(shù)據(jù)填入fifo,中斷里自動發(fā)送。我一般都是采用這種中斷加fifo的收發(fā)方式。中斷就像是后臺操作一樣,在主程序的流程中,不用刻意去關(guān)注中斷方式發(fā)送了沒有,何時接收等,而查詢方式是在主程序流程中不斷查看是否接收到了數(shù)據(jù),一般用while不斷循環(huán)查看。中斷方式可以更高效利用CPU ,節(jié)省CPU的時間,查詢就會增加CPU負擔。
02
按鍵模塊
查看原理圖,矩陣按鍵管腳如下:
矩陣鍵盤管腳定義及初始化:
void keyboard_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; GPIO_InitStructure.GPIO_Pin = ROW0_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = ROW0_GPIO_MODE; GPIO_Init(ROW0_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ROW1_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = ROW1_GPIO_MODE; GPIO_Init(ROW1_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = COL0_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = COL0_GPIO_MODE; GPIO_Init(COL0_GPIO_PORT, &GPIO_InitStructure); SetCol(0); GPIO_InitStructure.GPIO_Pin = COL1_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = COL1_GPIO_MODE; GPIO_Init(COL1_GPIO_PORT, &GPIO_InitStructure); SetCol(1);}
矩陣鍵盤鍵值讀?。?
u8 keyboard_GetCurrentKey( void){ u8 kbVal; u8 rowIndex; u8 colIndex; kbVal = KEY_noKey; for(colIndex = 0; colIndex < COL_NUM; colIndex ++)//按列查詢 { ClrCol(colIndex);//列線置低 for (rowIndex=0; rowIndex < ROW_NUM; rowIndex ++)//按行掃描 { if (!RowVal(rowIndex))//讀當前行電平 { kbVal = KEY_VAL[rowIndex][colIndex];//有值返回,并跳出循環(huán) break; } } SetCol(colIndex);//列線置高 if (kbVal != KEY_noKey) { break; } } return(kbVal);}
可以在主函數(shù)中輪詢鍵值進行處理,也可以在定時器中斷中輪詢鍵值。在中斷中的不要寫耗時操作或者加延時。在定時中斷輪詢鍵值一般也是配合fifo使用。代碼如下:
//2ms定時器void TIM5_IRQHandler(void){ if (TIM_GetFlagStatus(TIM5, TIM_IT_Update)) { TIM_ClearFlag(TIM5, TIM_IT_Update); ScanKeyDown();//處理按鍵中斷 }}
void ScanKeyDown(void){ g_keyPara.currentLcdKey = keyboard_GetCurrentKey(); //讀取鍵值 g_keyPara.keyFlag <<= 1; if(g_keyPara.currentLcdKey != KEY_noKey) { g_keyPara.keyFlag ++; } if (!g_keyPara.longLcdKeyFlag)//長按和短按處理 和短按的去抖處理 { if (g_keyPara.currentLcdKey == KEY_noKey) { if ((g_keyPara.shortLcdKeyTimer == 0)&&g_keyPara.shortLcdKey != 0) { fifo_DataIn(KB_FIFO,g_keyPara.shortLcdKey); //鍵值進fifo隊列等待處理 } g_keyPara.enterLongLcdKeyTimer = ENTER_LONG_KEY_TIME; g_keyPara.shortLcdKeyTimer = SHORT_KEY_TIME; } else { if (g_keyPara.shortLcdKeyTimer > 0) { g_keyPara.shortLcdKeyTimer --; if (g_keyPara.shortLcdKeyTimer == 0) { g_keyPara.shortLcdKey = g_keyPara.currentLcdKey; } } if(g_keyPara.enterLongLcdKeyTimer > 0) { g_keyPara.enterLongLcdKeyTimer --; if (g_keyPara.enterLongLcdKeyTimer == 0) { g_keyPara.longLcdKeyIntervalTimer = LONG_KEY_INTERVAL_TIME; g_keyPara.longLcdKeyFlag = 1; g_keyPara.longLcdKey = g_keyPara.currentLcdKey; fifo_DataIn(KB_FIFO,g_keyPara.longLcdKey+0x20);//鍵值進fifo隊列等待處理 } } } } else { if (g_keyPara.currentLcdKey == g_keyPara.longLcdKey) { if (g_keyPara.longLcdKeyIntervalTimer > 0) { g_keyPara.longLcdKeyIntervalTimer --; if (g_keyPara.longLcdKeyIntervalTimer == 0) { fifo_DataIn(KB_FIFO,g_keyPara.longLcdKey+0x20); //鍵值進fifo隊列等待處理 } } } else { g_keyPara.longLcdKeyFlag = 0; g_keyPara.longLcdKey = KEY_noKey; g_keyPara.shortLcdKey = KEY_noKey; g_keyPara.shortLcdKeyTimer = SHORT_KEY_TIME; g_keyPara.enterLongLcdKeyTimer = ENTER_LONG_KEY_TIME; g_keyPara.longLcdKeyIntervalTimer = LONG_KEY_INTERVAL_TIME; } }}
/ The End /
本文主要介紹了串口模塊和矩陣鍵盤模塊的管腳配置和初始化,并簡要介紹了各模塊的中斷使用方法。如有疑問,歡迎留言討論。
本文由【嵌入式案例Show】原創(chuàng)出品,未經(jīng)許可,請勿轉(zhuǎn)載
免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!