stm32 普通IO口模擬串口通信


普通IO口模擬串口通信

  • 串口通信協議  

  1. 串口傳輸 默認 波特率9600 1起始位 1停止位 其他0 數據位是8位(注意圖上的給錯了)。

  2. 傳輸時,從起始位開始,從一個數據的低位(LSB)開始發送,如圖從左向右的順序,對電平拉高或拉低,最后停止位時拉高。
  3. 波特率大小,改變延時時間即可。例如9600 波特率    根據公式 : 1/9600=0.000104s(大致) 也就是說每發送1bit延時104us (下面我用9600波特率來說,代碼用的是19200)
  4. 串口發送       將電平拉低 延時104us(視為 起始位 0   傳輸數據正式開始)  其中數據我發送的是16進制數據(8bit  一字節  例如10001000)  將想要發的數據按照二進制的‘0’‘1’高低電平的方式,每發送1bit 延時104us   直到發送完到終止位 將電平拉高視為一包數據傳輸結束。(根據需求更改即可)
  5. 串口接收    (稍微麻煩一些) 兩種方法:第一種可以用定時中斷,每隔104us開啟一次定時中斷,中斷函數內進行高低電平判斷,將這些bit存儲最后轉換成需要的數據。第二種,用外部中斷處理函數,外部中斷設置同時開啟上升沿下降沿,思路:根據上升下降的電平跳變分析。比如說,觸發外部中斷后檢測電平高低,記錄一下當前時間,然后再進入外部中斷后 計算出總共幾個bit   (兩個沿跳變之間的時間 =現在記錄的時間 — 之前記錄的時間        bit=這個時間/104us)  ,知道這個就可以轉換數據了。
  6. 定時中斷邏輯相對外部中斷而言簡單好寫,但是數據多的時候准確率下降很多,容易丟數據(因為定時中斷畢竟用計時開啟中斷,不可能時間准確每104us開啟一次,數據一多時間誤差大,自然丟包。可以嘗試每發一串數據,重新計時校准一次)。外部中斷較為准確,檢測的高低電平跳變較為明顯唯一,一個跳變就是一個數據,只是分析情況比較多。
  //IO模擬串口初始化
1
void IRrec_Init(){ 2 3 4 EXTI_InitTypeDef EXTI_InitStructure; 5 NVIC_InitTypeDef NVIC_InitStructure; 6 GPIO_InitTypeDef GPIO_InitStructure; 7 8 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC時鍾 9 10 11 //IR TX C9 使能 12 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 13 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 14 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 15 GPIO_Init(GPIOC, &GPIO_InitStructure); 16 GPIO_SetBits(GPIOC, GPIO_Pin_9);// 引腳拉高 17 18 19 //IR RX C8 20 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); 21 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; 22 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 23 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 24 GPIO_Init(GPIOC, &GPIO_InitStructure); 25 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource8); 26 27 EXTI_InitStructure.EXTI_Line=EXTI_Line8; 28 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; 29 EXTI_InitStructure.EXTI_Trigger= 30 EXTI_Trigger_Rising_Falling; 31 EXTI_InitStructure.EXTI_LineCmd=ENABLE; 32 EXTI_Init(&EXTI_InitStructure); 33 34 NVIC_InitStructure.NVIC_IRQChannel=EXTI9_5_IRQn; 35 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2; 36 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; 37 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 38 NVIC_Init(&NVIC_InitStructure); 39 40 }
 1 void IR_SendByte(u8 val)//發送bit位
 2 {
 3     u16 i;
 4     
 5     IRSEND=0;//拉低 開始傳輸
 6     SysTick_Delay_Us(53);//波特率根據延時在設置  19200波特率   
 7     
 8     for(i=0;i<8;i++)
 9     {
10         if(val&0x1)
11         {
12             IRSEND=1;
13         }
14         else
15         {
16             IRSEND=0;
17         }
18
19         val>>=1;
20         SysTick_Delay_Us(53);
21     }
22     
23     IRSEND=1;
24     SysTick_Delay_Us(53);
25 }
26 
27 
28 void IR_SendStr(u8*st,u16 len){//在這填入16位數據即可
29     int i=0;
30     while ((len--)!=0)
31     {  
32         IR_SendByte(st[i]);
33         i++;
34     }
35 
36 }
  1 u8 IRREC_RX_BUF[64]={0};    //接收緩沖,最大64個字節.
  2     //接收到的數據長度
  3     u8 IRREC_RX_CNT=0; 
  4 
  5 char rebit=stopbit;//記錄接收一個字節的二進制位所處何種位置
  6 u8 Recev[8]={0};//記錄接收的一個字節的二進制流
  7 
  8 static volatile unsigned long long m_rx_previous_time = 0;//上一次進入中斷時間
  9 static volatile unsigned char m_rx_begin_f = 0;//開始一個字節的接收標志 0-無數據開始接收 1-有數據開始接收
 10 void EXTI9_5_IRQHandler(void){
 11 
 12     if(EXTI_GetITStatus(EXTI_Line8)!=RESET)
 13     {
 14         unsigned char skip_index = 0;
 15         unsigned char i = 0;
 16         unsigned char temp_bin = 0;//用於記錄二進制值
 17         unsigned long long current_time = sys_micros();//記下此刻時間
 18         unsigned short interval_time = current_time - m_rx_previous_time;//計算一個狀態持續的時長 
 19         m_rx_previous_time = current_time;//為下次計算時長做准備
 20         
 21         //當前未開始一個字節的接收且此時為下降沿
 22         if(rebit == 10)//10 當數據不合法時或者結束傳輸時 rebit值設為10
 23         {
 24             if(!PCin(8))//下降沿
 25             {
 26                 rebit = 0;//記下開始接收
 27                 m_rx_begin_f = 1;
 28                 debug_led(1,LED_TOGGLE);
 29             }
 30         }
 31         //已經開始接收
 32         else
 33         {
 34             //上一狀態為起始位
 35             if(!rebit)//起始位0
 36             {
 37                 //計算二進制數據的個數
 38                 skip_index = (interval_time/50)-1;
 39 
 40                 //個數合法
 41                 if(skip_index <= 9)
 42                 {
 43                     //根據狀態保持時間更新接收值               
 44                     for(i = 0;i < skip_index;i++)
 45                     {
 46                         Recev[i] = 0;
 47                     
 48                     }
 49 
 50                     //更新接收二進制位的下標
 51                     rebit = skip_index;
 52                     
 53                 }
 54                 //不合法-重新接收
 55                 else 
 56                 {
 57                     rebit = 10;
 58                     m_rx_begin_f = 0;
 59                     
 60                     
 61                 }            
 62             }
 63             //上一狀態為數據位
 64             else
 65             {
 66                 //計算二進制數據的個數
 67                 skip_index = interval_time/50;
 68 
 69                 //數據不合法-重新接收
 70                 if((skip_index+rebit) > 9)//所處位置+數據個數 判斷數據是否超10 合法判斷
 71                 {
 72                     //printf("skip_index %d   rebit=%d \r\n",skip_index,rebit);
 73                     rebit = 10;
 74                     m_rx_begin_f = 0;
 75                     debug_led(3,LED_TOGGLE);
 76                 }
 77                 //數據合法
 78                 else
 79                 {
 80                     //當前為高電平
 81                     if(PCin(8))
 82                     {
 83                      temp_bin = 1;//0
 84                     }
 85                     else
 86                     {
 87                      temp_bin = 0;//1 change
 88                     }
 89                     debug_led(2,LED_TOGGLE);
 90                     for(i = 0;i < skip_index ;i++)//根據幾個數據 給予相應的位
 91                     {
 92                         Recev[rebit+i+1] = temp_bin;//change +1
 93                         rebit++;
 94             
 95                     }
 96                 }
 97                 
 98                 //數據已接收至結束位
 99                 if(rebit >= 8 )//=8>?
100                 {
101                     if(IRREC_RX_CNT < 64)
102                     {
103                         IRREC_RX_BUF[IRREC_RX_CNT++]     = (Recev[7] << 7) |(Recev[6] << 6)| (Recev[5] << 5)| (Recev[4] << 4)| (Recev[3] << 3) |(Recev[2] << 2) |(Recev[1] << 1) |Recev[0];
104                         
105                     }
106                     rebit = 10;
107                     m_rx_begin_f = 0;
108 
109                     
110                 }
111                 
112             }
113         }
114         
115 
116         #endif
117         EXTI_ClearITPendingBit(EXTI_Line8);//清除中斷掛起標志位
118 
119     }
120 
121 }

 

用於知識梳理積累,寫的比較隨意  

有問題可以發郵箱聯系我   udpmeettcp@163.com 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM