久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 6170|回復: 19
打印 上一主題 下一主題
收起左側

STM32串口控制LED燈閃爍或者呼吸效果

  [復制鏈接]
回帖獎勵 5 黑幣 回復本帖可獲得 5 黑幣獎勵! 每人限 1 次
跳轉到指定樓層
樓主
ID:703937 發表于 2020-8-24 12:05 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
目錄


  • 1、準備工作
  • 2、思路分析
  • 3、實際操作
  • 4、小結



1、準備工作

1.首先我們需要準備32的最小系統板或者開發板。
2.準備一個LED燈(如果使用板子上的燈來實現則不需要,下面我是使用最小系統板上的LED燈來實現)。
3.若干杜邦線。
4.軟件方面的準備,我是直接使用開源PWM源碼進行修改。


2、思路分析

一、使用串口調試助手向單片機發送數據(這個數據可以是一個字符,也可以是字符串,根據個人需求),我們發送的數據被單片機接收到后,會被保存在數據緩沖區USART_RX_BUF這個函數中。
二、我們的數據是存在USART_RX_BUF函數中,只要我們對USART_RX_BUF函數中的數據進行判斷就可以讓它實現不同的功能,這個判斷可以按位操作,也可以使用數組的方式進行判斷。
三、主函數中寫入我們需要實現的功能函數,主要使用IF判斷語句,來進行判斷。
下面來看看實際操作。


3、實際操作

1)如果你也是使用開源的PWM模板的話,第一步就可以省略了,第一步主要做一些使能串口和定義串口,定時器等的工作,我這里我使用的是定時器3的通道2——PB5(部分重映射,因為最小系統板的LED燈是對應PC13口的,到時候看效果還要使用一根杜邦線把PB5和PC13連在一起。如果自己準備了LED的小伙伴也可以直接接自己的LED但是最好要接一個保護電阻,還有要與單片機共地哦)這些都是開源模板里面已經幫我們定義好的,我們直接使用就行。如果是想自己寫的小伙伴開源參考下面的代碼

GPIO_InitTypeDef GPIO_InitStructure;

        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

        TIM_OCInitTypeDef  TIM_OCInitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        //使能定時器3時鐘

         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外設和AFIO復用功能模塊時鐘

        GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5   

   //設置該引腳為復用輸出功能,輸出TIM3 CH2的PWM脈沖波形        GPIOB.5

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //復用推挽輸出

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

   //初始化TIM3

        TIM_TimeBaseStructure.TIM_Period = arr; //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值

        TIM_TimeBaseStructure.TIM_Prescaler =psc; //設置用來作為TIMx時鐘頻率除數的預分頻值

        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設置時鐘分割:TDTS = Tck_tim

        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式

        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位

        //初始化TIM3 Channel2 PWM模式         

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時器模式:TIM脈沖寬度調制模式2

         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能

        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高

        TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根據T指定的參數初始化外設TIM3 OC2

        TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的預裝載寄存器

        TIM_Cmd(TIM3, ENABLE);  //使能TIM3

上面這串代碼就是使能了定時器3的通道2 ,和配置了相關的GPIO口。這就完成了第一步。
2)使能串口和配置串口,USART1_TX --GPIOA.9(發送);USART1_RX—GPIOA.10(接收),串口1的發生和接收分別對應著PA9和PA10,所以我們要使能和配置這兩個口,把PA9配置成輸出口,PA10配置成輸入口。然后還要使能中斷,其實在這個項目中,中斷不是必要的 ,但是最好也要搞一下。還要寫中斷服務函數,根據自己需要寫,我這里我只是把它用作了判斷數據是否接收成功。如果對應串口這個不是很了解的,也可以看我上一篇文章,是介紹串口和串口中斷的。分析到這些就OK了,下面上代碼。


  1. <font face="-apple-system, SF UI Text, Arial, PingFang SC, Hiragino Sans GB, Microsoft YaHei, WenQuanYi Micro Hei, sans-serif"><font color="#4d4d4d"> GPIO_InitTypeDef GPIO_InitStructure;
  2.         USART_InitTypeDef USART_InitStructure;
  3.         NVIC_InitTypeDef NVIC_InitStructure;
  4.          
  5.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);        //使能USART1,GPIOA時鐘
  6.   
  7.         //USART1_TX   GPIOA.9
  8.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  9.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  10.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //復用推挽輸出
  11.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
  12.    
  13.   //USART1_RX          GPIOA.10初始化
  14.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  15.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
  16.   GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  17.   
  18.         //Usart1 NVIC 配置
  19.   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  20.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優先級3
  21.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子優先級3
  22.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
  23.         NVIC_Init(&NVIC_InitStructure);        //根據指定的參數初始化VIC寄存器
  24.   
  25.    //USART 初始化設置

  26.         USART_InitStructure.USART_BaudRate = bound;//串口波特率
  27.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式
  28.         USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個停止位
  29.         USART_InitStructure.USART_Parity = USART_Parity_No;//無奇偶校驗位
  30.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬件數據流控制
  31.         USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;        //收發模式

  32.   USART_Init(USART1, &USART_InitStructure); //初始化串口1
  33.   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
  34.   USART_Cmd(USART1, ENABLE);                    //使能串口1 </font></font>
復制代碼
上面這些是串口的基本配置,下面是中斷服務函數

  1. void USART1_IRQHandler(void)                        //串口1中斷服務程序
  2.         {
  3.         u8 Res;
  4. #if SYSTEM_SUPPORT_OS                 //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
  5.         OSIntEnter();   
  6. #endif
  7.         if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
  8.                 {
  9.                 Res =USART_ReceiveData(USART1);        //讀取接收到的數據
  10.                
  11.                 if((USART_RX_STA&0x8000)==0)//接收未完成
  12.                         {
  13.                         if(USART_RX_STA&0x4000)//接收到了0x0d
  14.                                 {
  15.                                 if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
  16.                                 else USART_RX_STA|=0x8000;        //接收完成了
  17.                                 }
  18.                         else //還沒收到0X0D
  19.                                 {        
  20.                                 if(Res==0x0d)USART_RX_STA|=0x4000;
  21.                                 else
  22.                                         {
  23.                                         USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
  24.                                         USART_RX_STA++;
  25.                                         if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收         
  26.                                         }                 
  27.                                 }
  28.                         }                    
  29.      }
  30. #if SYSTEM_SUPPORT_OS         //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
  31.         OSIntExit();                                                                                          
  32. #endif
  33. }
復制代碼
如果想要主函數中比較簡潔的話,也可以把判斷的代碼放到中斷服務函數里面來,每次我們從串口發送一個數據過來,如果你寫了中斷的話,它都會進行中斷服務函數中的。
3)這個也是最重要的一步,前兩步在源碼中都有的,只要你根據你需要改就行。這步我們說如何控制LED的閃爍或者是呼吸的效果。我使用的是一個位一個位的判斷,這樣子比較的燒芯片,但是我當時想到的是這個辦法,后面我又知道可以使用數組進行判斷,這個數組函數是C語言中的,感興趣的小伙伴可以去查查,我這里主要講燒芯片的辦法,首先我先判斷串口調試助手發送進來的是不是“huxi”這個數據,如果是我就會令一個變量,這里是t,t=1,這樣后面我們就可以直接判斷t是否等于1來判斷要不要實現呼吸這個效果了,后面需要清除接收標記 USART_RX_STA=0;這樣之后串口才能重新接收數據。

  1. if(USART_RX_BUF[0]=='h'&&USART_RX_BUF[1]=='u'&&USART_RX_BUF[2]=='x'
  2.                                 &&USART_RX_BUF[3]=='i')
  3.                         {
  4.                         
  5.                                 t=1;
  6.                                 USART_RX_STA=0;
  7. //                                printf("t2.txt=\"呼吸\"\xff\xff\xff");

  8.                         }
復制代碼
  1. if(t==1)
  2.                 {
  3.                         delay_ms(10);//去抖動
  4.                 if(dir)led0pwmval++;
  5.                 else led0pwmval--;

  6.                  if(led0pwmval>200)dir=0;
  7.                 if(led0pwmval==0)dir=1;                                                                                 
  8.                 TIM_SetCompare2(TIM3,led0pwmval);

  9.                                 
  10.                 }
復制代碼
上面這兩個代碼就是實現呼吸燈效果的,閃爍效果的做法跟呼吸燈是一樣的,也是先進行判斷,然后調用判斷結果,我這里是判斷接收是否等于“shanshuo”這個數據,如果等于t=0,后面調用t這個變量就可以了,話不多說,上代碼。
  1. else if(USART_RX_BUF[0]=='s'&&USART_RX_BUF[1]=='h'&&USART_RX_BUF[2]=='a'
  2.                                 &&USART_RX_BUF[3]=='n'&&USART_RX_BUF[4]=='s'&&USART_RX_BUF[5]=='h'&&USART_RX_BUF[6]=='u'&&USART_RX_BUF[7]=='o')
  3.                         {
  4.                           
  5.                                 t=0;
  6.                                 USART_RX_STA=0;        
  7.                         
  8.                         }
復制代碼
  1. if(t==0)
  2.         {
  3.                 TIM_SetCompare2(TIM3,0);
  4.     delay_ms(300);
  5.    TIM_SetCompare2(TIM3,899);
  6.           delay_ms(300);


  7.         }
復制代碼
這樣使用兩次判斷就可以把這兩個功能都實現了。不過有一個小問題是,我們這樣子接收判斷是把原來存在數據緩沖區USART_RX_BUF中的數據給覆蓋掉的,如果前一個數據的長度比后一個要長,那就會覆蓋不完,最好還有加一個清除函數,這里介紹一種辦法使用運行庫函數memset():memset(str, 0, sizeof(str));這樣就可以把緩沖區的數據清除掉,當然還有其他辦法,但是我就想到這個,可能不好用。但是我們這個項目里面覆蓋完不完并不會影響結果,所以也可以用,不過在需要把數據打印到串口這樣的項目中,就很有必要把之前數據給清除掉,不然容易出錯。
為了代碼的完整,下面我把整個主函數的代碼給貼出來,給各位伙伴參考。
  1. int main(void)
  2. {               
  3.    
  4.          u16 t;  
  5.          u16 led0pwmval=0;
  6.         u8 dir=1;        
  7.         delay_init();                     //延時函數初始化         
  8.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);          //設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
  9.         uart_init(115200);         //串口初始化為115200
  10.          LED_Init();                             //LED端口初始化
  11.          TIM3_PWM_Init(899,0);         //不分頻。PWM頻率=72000000/900=80Khz
  12.   
  13.          while(1)
  14.         {

  15.                         if(USART_RX_BUF[0]=='h'&&USART_RX_BUF[1]=='u'&&USART_RX_BUF[2]=='x'
  16.                                 &&USART_RX_BUF[3]=='i')
  17.                         {
  18.                         
  19.                                 t=1;
  20.                                 USART_RX_STA=0;


  21.                         }
  22.                         else if(USART_RX_BUF[0]=='s'&&USART_RX_BUF[1]=='h'&&USART_RX_BUF[2]=='a'
  23.                                 &&USART_RX_BUF[3]=='n'&&USART_RX_BUF[4]=='s'&&USART_RX_BUF[5]=='h'&&USART_RX_BUF[6]=='u'&&USART_RX_BUF[7]=='o')
  24.                         {
  25.                           
  26.                                 t=0;
  27.                                 USART_RX_STA=0;        
  28.                         
  29.                         }
  30.                

  31.                 if(t==1)
  32.                 {
  33.                         delay_ms(10);//去抖動
  34.                 if(dir)led0pwmval++;
  35.                 else led0pwmval--;

  36.                  if(led0pwmval>200)dir=0;
  37.                 if(led0pwmval==0)dir=1;                                                                                 
  38.                 TIM_SetCompare2(TIM3,led0pwmval);

  39.                                 
  40.                 }
  41.         if(t==0)
  42.         {
  43.                 TIM_SetCompare2(TIM3,0);
  44.     delay_ms(300);
  45.    TIM_SetCompare2(TIM3,899);
  46.           delay_ms(300);


  47.         }
  48.                                 
  49.         
  50. }
  51. }
復制代碼

4、小結

1.在這個項目中要注意把PB5和PC13用杜邦線連到一樣哦,不然就看不到效果啦。
2.還有一個易錯點就是,在閃爍這個功能代碼中,很多人首先想到的肯定是讓那個GPIO口的電平置高或者置低來控制燈的閃爍,但是這樣子的話,你就不可以只用一個燈來實現呼吸和閃爍之間的轉換了,你需要使用兩個燈,一個呼吸一個閃爍,這樣子是比較麻煩的。但是也根據個人需要吧,如果想要只用一個燈實現兩個效果,就使用上面的方法,呼吸和閃爍都使用定時器3通道2來控制。這樣就可以達到轉換自如了。
3.就是數據覆蓋的問題,這個也是根據你要做的項目要解決吧,可以清除,也可以不用。
4.上面的辦法只是控制呼吸和閃爍的一種辦法,或許復雜了,希望有更加簡單辦法的大佬指導一下,我也是剛剛學習,如有不懂的,可以私信交流,分享到此,謝謝.


評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏5 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:710888 發表于 2020-8-25 08:02 | 只看該作者
115200的波特率每ms至少能夠傳輸1字節數據
如果在main函數中處理命令,僅軟延時就有600ms,不建議這么寫
回復

使用道具 舉報

板凳
ID:703937 發表于 2020-9-2 12:54 | 只看該作者
seanking 發表于 2020-8-25 08:02
115200的波特率每ms至少能夠傳輸1字節數據
如果在main函數中處理命令,僅軟延時就有600ms,不建議這么寫

好的,感謝指點
回復

使用道具 舉報

地板
ID:711352 發表于 2020-9-3 14:19 | 只看該作者
樓主呼吸燈控制寫的挺詳細的,學習一下
回復

使用道具 舉報

5#
ID:65657 發表于 2020-9-3 17:33 | 只看該作者
想做個呼吸燈的玩具,正好用上
回復

使用道具 舉報

6#
ID:242804 發表于 2020-9-3 18:48 | 只看該作者
樓主這個成本有點大呀,可以通過多點的LED來做更好的
回復

使用道具 舉報

7#
ID:260557 發表于 2020-9-17 17:11 | 只看該作者
試驗下先。。。。。。
回復

使用道具 舉報

8#
ID:94134 發表于 2020-9-18 10:13 | 只看該作者
一個燈閃也要弄得這么復雜嗎
回復

使用道具 舉報

9#
ID:822482 發表于 2020-9-23 18:30 | 只看該作者
串口接收數據那里寫的不錯,解決了我的迷惑
回復

使用道具 舉報

10#
ID:742521 發表于 2020-9-24 14:45 | 只看該作者
jmpw 發表于 2020-9-18 10:13
一個燈閃也要弄得這么復雜嗎

是漸變
回復

使用道具 舉報

11#
ID:714744 發表于 2020-12-23 13:14 | 只看該作者
講的真好
回復

使用道具 舉報

12#
ID:867221 發表于 2020-12-28 14:07 | 只看該作者
感謝樓主的分享。收藏備用、學習
回復

使用道具 舉報

13#
ID:702127 發表于 2020-12-28 15:57 | 只看該作者
學習了,講解很詳細,最近正在學習STM32,這個教程串口、定時器和PWM都用到了。
回復

使用道具 舉報

14#
ID:514987 發表于 2020-12-28 16:12 | 只看該作者
樓主控制寫的挺詳細的,學習一下
回復

使用道具 舉報

15#
ID:417524 發表于 2021-1-8 16:31 | 只看該作者
這個很適合學習,正好需要

回復

使用道具 舉報

16#
ID:711352 發表于 2021-1-8 17:38 | 只看該作者
試一下,寫的挺詳細的
回復

使用道具 舉報

17#
ID:661314 發表于 2021-2-2 13:34 | 只看該作者
USART_RX_BUF[0]   USART_RX_STA 是在哪個地方定義的
回復

使用道具 舉報

18#
ID:882291 發表于 2021-2-2 17:44 | 只看該作者
可以通過多點的LED來做更好的
回復

使用道具 舉報

19#
ID:610005 發表于 2021-2-9 09:55 | 只看該作者
呼吸燈控制寫的挺詳細的,學習一下
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日本久久视频 | 成人av播放| 成年人在线视频 | www视频在线观看 | 97在线超碰 | 2022精品国偷自产免费观看 | 天天操综合网 | 黑人精品欧美一区二区蜜桃 | 成人av网站在线观看 | eeuss国产一区二区三区四区 | 欧美激情精品久久久久 | 日本一区二区电影 | 亚洲精品黄色 | 亚洲精品日韩一区二区电影 | 国产区在线免费观看 | 成人av免费看 | 国产在线精品一区二区三区 | 高清黄色网址 | 在线播放国产一区二区三区 | 伊人免费观看视频 | 一久久久 | 欧美精品91爱爱 | 中文字幕一区在线 | 一区二区三区欧美在线观看 | 欧美精品久久久 | av大片在线观看 | 在线免费观看黄色 | 国产在线精品一区二区三区 | a级片网站 | 成人在线视频免费看 | 欧美日韩一区二区视频在线观看 | 日韩av网址在线观看 | 欧美日韩亚洲国产 | 国产精品一码二码三码在线 | 一区二区三区韩国 | 婷婷成人在线 | 欧美日韩在线观看视频网站 | 欧美性久久| 伊人精品 | 伊人久久大香线 | 99精品在线观看 |