1. 實驗目的
1.串口助手發(fā)送一個數(shù)(發(fā)送的形式是ascii碼),最后除以100展示這個數(shù),如發(fā)送一個-29987,最后要展示出-299.87。
2.串口助手發(fā)送一個數(shù)(發(fā)送的形式是16進制),最后除以100展示這個數(shù),如發(fā)送一個-3,最后要展示出-0.03。
其中串口是USART1,其端口是GPIOA,引腳是PIN9、PIN10,一個用來收數(shù)據(jù),一個用來發(fā)收據(jù)。
2. 實驗流程
初始化串口;
編寫數(shù)據(jù)轉換函數(shù)函數(shù);
編寫接收數(shù)據(jù)中斷函數(shù)和空閑中斷函數(shù)。
2.1 初始化串口
//配置中斷函數(shù),這個函數(shù)下面有調用
void EXTI_NVIC_Config(void){
//NVIC初始化結構體
NVIC_InitTypeDef NVIC_InitStruct;
//設置中斷優(yōu)先級的分組
//就是設置主搶占優(yōu)先級和子搶占優(yōu)先級各是幾,這里是分組為1,代表主優(yōu)先級可以是0和1(就是1個位來設置主優(yōu)先級),子優(yōu)先級是0-7,是2的3次方
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置USART為中斷源
NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
//配置搶占優(yōu)先級
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
//配置子優(yōu)先級
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
//使能中斷
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
//串口初始化函數(shù)
void USART_Config(void){
//1.初始化GPIO(PA9(接串口1的TX引腳),這里是PA10(接串口1的RX引腳))
//初始化結構體 GPIO_InitStruct
//里面是GPIO的速度,上下拉,輸出類型等
GPIO_InitTypeDef GPIO_InitStruct;
//USART結構體
USART_InitTypeDef USART_InitStruct;
//打開GPIOA時鐘(一般開時鐘要放到前面的位置,然后再是設置上拉,輸出這些)
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能時鐘必須放到前面,不然后面的操作不會使燈點亮
//打開USART1時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1時鐘
//復位串口1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1); //PA9 復用為 USART1
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1); //PA10 復用為 USART1
//驅動是哪個引腳 PA9/PA10
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
//模式是復用功能
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
//輸出的速度
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
//推挽復用輸出
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
//上拉
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
//變量獲取它的指針,取地址就行(&)
GPIO_Init(GPIOA,&GPIO_InitStruct);
//2.初始化串口
//使能串口時鐘 (放在最上面了)
//配置波特率
USART_InitStruct.USART_BaudRate = 115200; //設置波特率115200
//配置針數(shù)據(jù)字長
USART_InitStruct.USART_WordLength = USART_WordLength_8b; //字長為8位數(shù)據(jù)格式
//配置停止位
USART_InitStruct.USART_StopBits = USART_StopBits_1; //設置為一個停止位
//配置校驗位
USART_InitStruct.USART_Parity = USART_Parity_No; //無奇偶校驗位
//配置硬件流控制
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不使用硬件流控制
//配置工作模式
USART_InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; //收發(fā)模式
//完成串口的初始化配置
USART_Init(USART1,&USART_InitStruct);
//串口中斷優(yōu)先級配置(初始化)
EXTI_NVIC_Config();
//使能串口接收中斷(中斷配置函數(shù)) 這是使能哪種中斷,比如在接收到數(shù)據(jù)的時候(RXNE 讀數(shù)據(jù)寄存器非空),我們要產生中斷
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //生成串口中斷 接收到數(shù)據(jù)就產生了中斷
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 開啟空閑中斷
//使能串口(串口使能函數(shù))
USART_Cmd(USART1,ENABLE);
}
2.2 編寫數(shù)據(jù)轉換函數(shù)函數(shù)
在寫轉換函數(shù)之前,先要看這個ASCII碼中的0123456789對應的是什么。在空閑中斷里面打印接收到的數(shù)據(jù),下面是部分代碼,詳細代碼參見2.3。
for(i = 0;i < 10; i++){
printf("value_10 = %x\n",rx_buff[i]);
}
memset(rx_buff,0,sizeof(rx_buff)); //清空數(shù)組
rx_cnt = 0; //數(shù)組指針置0
得到結果如下圖所示:
所以我們通過判斷接收過來的字節(jié),判斷這個值是哪個數(shù)字。
先找規(guī)律,這里是假設發(fā)送的數(shù)字是-29987,函數(shù)中傳入的值一個是數(shù)組,一個是數(shù)組的總索引值,這里取到的字節(jié)首先要減去0X30,得到這個數(shù)字是幾,然后再乘以10的幾次方,2在萬位上,需要乘以10000,它的索引值對應的是1,傳來的索引總數(shù)是6,所以乘的10次方應該是:10的次方數(shù) = 6(總索引值) - 1(2所在的索引值) - 1;9在千位上,需要乘以1000,它的索引值對應的是2,所以乘的10次方應該是:10的次方數(shù) = 6(總索引值) - 2(9所在的索引值) - 1;第二個9在百位上,需要乘以100,它的索引值對應的是3,所以乘的10次方應該是:10的次方數(shù) = 總索引值 - 3(9所在的索引值) - 1;以此類推。
如果是正數(shù)的話,假如是29987,2在萬位上,需要乘以10000,它的索引值對應的是1,傳來的索引總數(shù)是5,所以乘的10次方應該是:10的次方數(shù) = 5(總索引值) - 1(2所在的索引值) - 1;9在千位上,需要乘以1000,它的索引值對應的是2,傳來的索引總數(shù)是5,所以乘的10次方應該是:10的次方數(shù) = 5(總索引值) - 1(2所在的索引值) - 1;以此類推。
數(shù)據(jù)轉換函數(shù)函數(shù)(發(fā)送ASCII的形式的)如下:
void Value_Show(uint8_t* array, uint8_t rx_cnt) //傳入數(shù)組地址,數(shù)組的索引
{
uint8_t i;
uint8_t j;
uint16_t value_fu = 0;
uint16_t temp = 0;
uint8_t rx_buff1[10] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39};
if(array[0] == '-'){ //判斷接收的第一個字節(jié)是不是負數(shù),這里寫if(array[0] == 0X2d)也是可以的,負號的16進制就是0X2d
for(i = 1;i < rx_cnt; i++){
for(j= 0;j < sizeof(rx_buff1)/sizeof(rx_buff1[0]);j++){ //循環(huán)的次數(shù)是10
if(array[i] == rx_buff1[j]){ //判斷接收到的數(shù)據(jù)是那一個
value_fu += (rx_buff1[j] - 0X30) * pow(10,rx_cnt - i -1);
break;
}
}
}
printf("value_10 = %.2f\n",(float)-value_fu/100);
}else{ //接收的是正數(shù)
for(i = 0;i < rx_cnt; i++){
for(j= 0;j < sizeof(rx_buff1)/sizeof(rx_buff1[0]);j++){
if(array[i] == rx_buff1[j]){
value_fu += (rx_buff1[j] - 0X30) * pow(10,rx_cnt - i -1);
break;
}
}
}
printf("value_10 = %.2f\n",(float)value_fu/100);
}
}
數(shù)據(jù)轉換函數(shù)函數(shù)(發(fā)送的是16進制的)如下:
計算機中存放的整型數(shù)據(jù)都是按補碼的形式存放的,負數(shù)的補碼是其本身絕對值的原碼取反再加1。
~本身絕對值 + 1 = 負數(shù);現(xiàn)在求本身絕對值就是:本身絕對值 = ~(負數(shù) - 1);對應下面代碼的temp = ~(value - 1);文章來源:http://www.zghlxwxcb.cn/news/detail-422013.html
void Value_Show_16(uint8_t* array, uint8_t rx_cnt){
value = (rx_buff[0]<<8)|(rx_buff[1]); //拼接數(shù)據(jù)
//最高位為1代表的是負數(shù) &同為1的時候才為1
if(value &(1<<15) != 0){
temp = ~(value - 1);
printf("value_10 = %.2f\n",(float)-temp/100);
}
}
2.3 編寫接收數(shù)據(jù)中斷函數(shù)和空閑中斷函數(shù)
//接收數(shù)據(jù)中斷函數(shù)
void USART1_IRQHandler(void){
uint8_t i;
unsigned int data;
if(USART_GetITStatus(USART1,USART_IT_RXNE)){ //每當接收到1個字節(jié),會產生USART_IT_RXNE中斷
rx_buff[rx_cnt] = USART_ReceiveData(USART1); //把這個數(shù)據(jù)放到數(shù)組中去
rx_cnt++;
}
//空閑中斷函數(shù)
if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET){ //當接收到一幀數(shù)據(jù),就會產生USART_IT_IDLE中斷
data = USART1->SR; // 清空閑中斷
data = USART1->DR; //空閑中斷是在檢測到在數(shù)據(jù)收受后,總線上在一個字節(jié)的時間內沒有再接收到數(shù)據(jù)時發(fā)生
usart_idle_flag = 1; //產生空閑中斷,沒有用到
//Value_Show(rx_buff,rx_cnt); //ascii轉換函數(shù)
Value_Show_16(rx_buff,rx_cnt); //16進制轉換函數(shù)
memset(rx_buff,0,sizeof(rx_buff)); //清空數(shù)組
rx_cnt = 0; //數(shù)組索引置0
}
}
3. 實驗結果
以ASCII發(fā)送正數(shù)和負數(shù)如下圖所示:
以16進制發(fā)送正數(shù)和負數(shù)如下圖所示:文章來源地址http://www.zghlxwxcb.cn/news/detail-422013.html
到了這里,關于串口通信——串口助手發(fā)送正數(shù)/負數(shù)(以ascii碼的形式發(fā)送或者以16進制形式發(fā)送),最后展示出發(fā)送的數(shù)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!