標(biāo)題: STM32串口控制LED燈閃爍或者呼吸效果 [打印本頁(yè)]
作者: 新手在線求帶 時(shí)間: 2020-8-24 12:05
標(biāo)題: STM32串口控制LED燈閃爍或者呼吸效果
目錄
- 1、準(zhǔn)備工作
- 2、思路分析
- 3、實(shí)際操作
- 4、小結(jié)
1、準(zhǔn)備工作
1.首先我們需要準(zhǔn)備32的最小系統(tǒng)板或者開(kāi)發(fā)板。
2.準(zhǔn)備一個(gè)LED燈(如果使用板子上的燈來(lái)實(shí)現(xiàn)則不需要,下面我是使用最小系統(tǒng)板上的LED燈來(lái)實(shí)現(xiàn))。
3.若干杜邦線。
4.軟件方面的準(zhǔn)備,我是直接使用開(kāi)源PWM源碼進(jìn)行修改。
2、思路分析
一、使用串口調(diào)試助手向單片機(jī)發(fā)送數(shù)據(jù)(這個(gè)數(shù)據(jù)可以是一個(gè)字符,也可以是字符串,根據(jù)個(gè)人需求),我們發(fā)送的數(shù)據(jù)被單片機(jī)接收到后,會(huì)被保存在數(shù)據(jù)緩沖區(qū)USART_RX_BUF這個(gè)函數(shù)中。
二、我們的數(shù)據(jù)是存在USART_RX_BUF函數(shù)中,只要我們對(duì)USART_RX_BUF函數(shù)中的數(shù)據(jù)進(jìn)行判斷就可以讓它實(shí)現(xiàn)不同的功能,這個(gè)判斷可以按位操作,也可以使用數(shù)組的方式進(jìn)行判斷。
三、主函數(shù)中寫(xiě)入我們需要實(shí)現(xiàn)的功能函數(shù),主要使用IF判斷語(yǔ)句,來(lái)進(jìn)行判斷。
下面來(lái)看看實(shí)際操作。
3、實(shí)際操作
1)如果你也是使用開(kāi)源的PWM模板的話,第一步就可以省略了,第一步主要做一些使能串口和定義串口,定時(shí)器等的工作,我這里我使用的是定時(shí)器3的通道2——PB5(部分重映射,因?yàn)樽钚∠到y(tǒng)板的LED燈是對(duì)應(yīng)PC13口的,到時(shí)候看效果還要使用一根杜邦線把PB5和PC13連在一起。如果自己準(zhǔn)備了LED的小伙伴也可以直接接自己的LED但是最好要接一個(gè)保護(hù)電阻,還有要與單片機(jī)共地哦)這些都是開(kāi)源模板里面已經(jīng)幫我們定義好的,我們直接使用就行。如果是想自己寫(xiě)的小伙伴開(kāi)源參考下面的代碼
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定時(shí)器3時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); //使能GPIO外設(shè)和AFIO復(fù)用功能模塊時(shí)鐘
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射 TIM3_CH2->PB5
//設(shè)置該引腳為復(fù)用輸出功能,輸出TIM3 CH2的PWM脈沖波形 GPIOB.5
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //設(shè)置在下一個(gè)更新事件裝入活動(dòng)的自動(dòng)重裝載寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //設(shè)置用來(lái)作為T(mén)IMx時(shí)鐘頻率除數(shù)的預(yù)分頻值
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設(shè)置時(shí)鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計(jì)數(shù)模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據(jù)TIM_TimeBaseInitStruct中指定的參數(shù)初始化TIMx的時(shí)間基數(shù)單位
//初始化TIM3 Channel2 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //選擇定時(shí)器模式:TIM脈沖寬度調(diào)制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比較輸出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //輸出極性:TIM輸出比較極性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根據(jù)T指定的參數(shù)初始化外設(shè)TIM3 OC2
TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR2上的預(yù)裝載寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
上面這串代碼就是使能了定時(shí)器3的通道2 ,和配置了相關(guān)的GPIO口。這就完成了第一步。
2)使能串口和配置串口,USART1_TX --GPIOA.9(發(fā)送);USART1_RX—GPIOA.10(接收),串口1的發(fā)生和接收分別對(duì)應(yīng)著PA9和PA10,所以我們要使能和配置這兩個(gè)口,把PA9配置成輸出口,PA10配置成輸入口。然后還要使能中斷,其實(shí)在這個(gè)項(xiàng)目中,中斷不是必要的 ,但是最好也要搞一下。還要寫(xiě)中斷服務(wù)函數(shù),根據(jù)自己需要寫(xiě),我這里我只是把它用作了判斷數(shù)據(jù)是否接收成功。如果對(duì)應(yīng)串口這個(gè)不是很了解的,也可以看我上一篇文章,是介紹串口和串口中斷的。分析到這些就OK了,下面上代碼。
- <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;
- USART_InitTypeDef USART_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
-
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時(shí)鐘
-
- //USART1_TX GPIOA.9
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
-
- //USART1_RX GPIOA.10初始化
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
- GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
-
- //Usart1 NVIC 配置
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶占優(yōu)先級(jí)3
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優(yōu)先級(jí)3
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
- NVIC_Init(&NVIC_InitStructure); //根據(jù)指定的參數(shù)初始化VIC寄存器
-
- //USART 初始化設(shè)置
- USART_InitStructure.USART_BaudRate = bound;//串口波特率
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長(zhǎng)為8位數(shù)據(jù)格式
- USART_InitStructure.USART_StopBits = USART_StopBits_1;//一個(gè)停止位
- USART_InitStructure.USART_Parity = USART_Parity_No;//無(wú)奇偶校驗(yàn)位
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無(wú)硬件數(shù)據(jù)流控制
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式
- USART_Init(USART1, &USART_InitStructure); //初始化串口1
- USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開(kāi)啟串口接受中斷
- USART_Cmd(USART1, ENABLE); //使能串口1 </font></font>
復(fù)制代碼 上面這些是串口的基本配置,下面是中斷服務(wù)函數(shù)
- void USART1_IRQHandler(void) //串口1中斷服務(wù)程序
- {
- u8 Res;
- #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
- OSIntEnter();
- #endif
- if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數(shù)據(jù)必須是0x0d 0x0a結(jié)尾)
- {
- Res =USART_ReceiveData(USART1); //讀取接收到的數(shù)據(jù)
-
- if((USART_RX_STA&0x8000)==0)//接收未完成
- {
- if(USART_RX_STA&0x4000)//接收到了0x0d
- {
- if(Res!=0x0a)USART_RX_STA=0;//接收錯(cuò)誤,重新開(kāi)始
- else USART_RX_STA|=0x8000; //接收完成了
- }
- else //還沒(méi)收到0X0D
- {
- if(Res==0x0d)USART_RX_STA|=0x4000;
- else
- {
- USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
- USART_RX_STA++;
- if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數(shù)據(jù)錯(cuò)誤,重新開(kāi)始接收
- }
- }
- }
- }
- #if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
- OSIntExit();
- #endif
- }
復(fù)制代碼 如果想要主函數(shù)中比較簡(jiǎn)潔的話,也可以把判斷的代碼放到中斷服務(wù)函數(shù)里面來(lái),每次我們從串口發(fā)送一個(gè)數(shù)據(jù)過(guò)來(lái),如果你寫(xiě)了中斷的話,它都會(huì)進(jìn)行中斷服務(wù)函數(shù)中的。
3)這個(gè)也是最重要的一步,前兩步在源碼中都有的,只要你根據(jù)你需要改就行。這步我們說(shuō)如何控制LED的閃爍或者是呼吸的效果。我使用的是一個(gè)位一個(gè)位的判斷,這樣子比較的燒芯片,但是我當(dāng)時(shí)想到的是這個(gè)辦法,后面我又知道可以使用數(shù)組進(jìn)行判斷,這個(gè)數(shù)組函數(shù)是C語(yǔ)言中的,感興趣的小伙伴可以去查查,我這里主要講燒芯片的辦法,首先我先判斷串口調(diào)試助手發(fā)送進(jìn)來(lái)的是不是“huxi”這個(gè)數(shù)據(jù),如果是我就會(huì)令一個(gè)變量,這里是t,t=1,這樣后面我們就可以直接判斷t是否等于1來(lái)判斷要不要實(shí)現(xiàn)呼吸這個(gè)效果了,后面需要清除接收標(biāo)記 USART_RX_STA=0;這樣之后串口才能重新接收數(shù)據(jù)。
- if(USART_RX_BUF[0]=='h'&&USART_RX_BUF[1]=='u'&&USART_RX_BUF[2]=='x'
- &&USART_RX_BUF[3]=='i')
- {
-
- t=1;
- USART_RX_STA=0;
- // printf("t2.txt=\"呼吸\"\xff\xff\xff");
- }
復(fù)制代碼- if(t==1)
- {
- delay_ms(10);//去抖動(dòng)
- if(dir)led0pwmval++;
- else led0pwmval--;
- if(led0pwmval>200)dir=0;
- if(led0pwmval==0)dir=1;
- TIM_SetCompare2(TIM3,led0pwmval);
-
- }
復(fù)制代碼 上面這兩個(gè)代碼就是實(shí)現(xiàn)呼吸燈效果的,閃爍效果的做法跟呼吸燈是一樣的,也是先進(jìn)行判斷,然后調(diào)用判斷結(jié)果,我這里是判斷接收是否等于“shanshuo”這個(gè)數(shù)據(jù),如果等于t=0,后面調(diào)用t這個(gè)變量就可以了,話不多說(shuō),上代碼。- else if(USART_RX_BUF[0]=='s'&&USART_RX_BUF[1]=='h'&&USART_RX_BUF[2]=='a'
- &&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')
- {
-
- t=0;
- USART_RX_STA=0;
-
- }
復(fù)制代碼- if(t==0)
- {
- TIM_SetCompare2(TIM3,0);
- delay_ms(300);
- TIM_SetCompare2(TIM3,899);
- delay_ms(300);
-
- }
復(fù)制代碼 這樣使用兩次判斷就可以把這兩個(gè)功能都實(shí)現(xiàn)了。不過(guò)有一個(gè)小問(wèn)題是,我們這樣子接收判斷是把原來(lái)存在數(shù)據(jù)緩沖區(qū)USART_RX_BUF中的數(shù)據(jù)給覆蓋掉的,如果前一個(gè)數(shù)據(jù)的長(zhǎng)度比后一個(gè)要長(zhǎng),那就會(huì)覆蓋不完,最好還有加一個(gè)清除函數(shù),這里介紹一種辦法使用運(yùn)行庫(kù)函數(shù)memset():memset(str, 0, sizeof(str));這樣就可以把緩沖區(qū)的數(shù)據(jù)清除掉,當(dāng)然還有其他辦法,但是我就想到這個(gè),可能不好用。但是我們這個(gè)項(xiàng)目里面覆蓋完不完并不會(huì)影響結(jié)果,所以也可以用,不過(guò)在需要把數(shù)據(jù)打印到串口這樣的項(xiàng)目中,就很有必要把之前數(shù)據(jù)給清除掉,不然容易出錯(cuò)。
為了代碼的完整,下面我把整個(gè)主函數(shù)的代碼給貼出來(lái),給各位伙伴參考。
- int main(void)
- {
-
- u16 t;
- u16 led0pwmval=0;
- u8 dir=1;
- delay_init(); //延時(shí)函數(shù)初始化
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置NVIC中斷分組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)
- uart_init(115200); //串口初始化為115200
- LED_Init(); //LED端口初始化
- TIM3_PWM_Init(899,0); //不分頻。PWM頻率=72000000/900=80Khz
-
- while(1)
- {
- if(USART_RX_BUF[0]=='h'&&USART_RX_BUF[1]=='u'&&USART_RX_BUF[2]=='x'
- &&USART_RX_BUF[3]=='i')
- {
-
- t=1;
- USART_RX_STA=0;
- }
- else if(USART_RX_BUF[0]=='s'&&USART_RX_BUF[1]=='h'&&USART_RX_BUF[2]=='a'
- &&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')
- {
-
- t=0;
- USART_RX_STA=0;
-
- }
-
- if(t==1)
- {
- delay_ms(10);//去抖動(dòng)
- if(dir)led0pwmval++;
- else led0pwmval--;
- if(led0pwmval>200)dir=0;
- if(led0pwmval==0)dir=1;
- TIM_SetCompare2(TIM3,led0pwmval);
-
- }
- if(t==0)
- {
- TIM_SetCompare2(TIM3,0);
- delay_ms(300);
- TIM_SetCompare2(TIM3,899);
- delay_ms(300);
-
- }
-
-
- }
- }
復(fù)制代碼
4、小結(jié)
1.在這個(gè)項(xiàng)目中要注意把PB5和PC13用杜邦線連到一樣哦,不然就看不到效果啦。
2.還有一個(gè)易錯(cuò)點(diǎn)就是,在閃爍這個(gè)功能代碼中,很多人首先想到的肯定是讓那個(gè)GPIO口的電平置高或者置低來(lái)控制燈的閃爍,但是這樣子的話,你就不可以只用一個(gè)燈來(lái)實(shí)現(xiàn)呼吸和閃爍之間的轉(zhuǎn)換了,你需要使用兩個(gè)燈,一個(gè)呼吸一個(gè)閃爍,這樣子是比較麻煩的。但是也根據(jù)個(gè)人需要吧,如果想要只用一個(gè)燈實(shí)現(xiàn)兩個(gè)效果,就使用上面的方法,呼吸和閃爍都使用定時(shí)器3通道2來(lái)控制。這樣就可以達(dá)到轉(zhuǎn)換自如了。
3.就是數(shù)據(jù)覆蓋的問(wèn)題,這個(gè)也是根據(jù)你要做的項(xiàng)目要解決吧,可以清除,也可以不用。
4.上面的辦法只是控制呼吸和閃爍的一種辦法,或許復(fù)雜了,希望有更加簡(jiǎn)單辦法的大佬指導(dǎo)一下,我也是剛剛學(xué)習(xí),如有不懂的,可以私信交流,分享到此,謝謝.
作者: seanking 時(shí)間: 2020-8-25 08:02
115200的波特率每ms至少能夠傳輸1字節(jié)數(shù)據(jù)
如果在main函數(shù)中處理命令,僅軟延時(shí)就有600ms,不建議這么寫(xiě)
作者: 新手在線求帶 時(shí)間: 2020-9-2 12:54
好的,感謝指點(diǎn)
作者: 1244986336 時(shí)間: 2020-9-3 14:19
樓主呼吸燈控制寫(xiě)的挺詳細(xì)的,學(xué)習(xí)一下
作者: gentleyidao 時(shí)間: 2020-9-3 17:33
想做個(gè)呼吸燈的玩具,正好用上
作者: liding12356 時(shí)間: 2020-9-3 18:48
樓主這個(gè)成本有點(diǎn)大呀,可以通過(guò)多點(diǎn)的LED來(lái)做更好的
作者: fmqwh626 時(shí)間: 2020-9-17 17:11
試驗(yàn)下先。。。。。。
作者: jmpw 時(shí)間: 2020-9-18 10:13
一個(gè)燈閃也要弄得這么復(fù)雜嗎
作者: Beautiful_me 時(shí)間: 2020-9-23 18:30
串口接收數(shù)據(jù)那里寫(xiě)的不錯(cuò),解決了我的迷惑
作者: lovekmjb 時(shí)間: 2020-9-24 14:45
是漸變
作者: ggyu7 時(shí)間: 2020-12-23 13:14
講的真好
作者: 真是又菜又愛(ài)玩 時(shí)間: 2020-12-28 14:07
感謝樓主的分享。收藏備用、學(xué)習(xí)
作者: ii11nnocent 時(shí)間: 2020-12-28 15:57
學(xué)習(xí)了,講解很詳細(xì),最近正在學(xué)習(xí)STM32,這個(gè)教程串口、定時(shí)器和PWM都用到了。
作者: spookerst 時(shí)間: 2020-12-28 16:12
樓主控制寫(xiě)的挺詳細(xì)的,學(xué)習(xí)一下
作者: 格林楓景 時(shí)間: 2021-1-8 16:31
這個(gè)很適合學(xué)習(xí),正好需要
作者: 1244986336 時(shí)間: 2021-1-8 17:38
試一下,寫(xiě)的挺詳細(xì)的
作者: 13978150572 時(shí)間: 2021-2-2 13:34
USART_RX_BUF[0] USART_RX_STA 是在哪個(gè)地方定義的
作者: jack-tommy 時(shí)間: 2021-2-2 17:44
可以通過(guò)多點(diǎn)的LED來(lái)做更好的
作者: n_n 時(shí)間: 2021-2-9 09:55
呼吸燈控制寫(xiě)的挺詳細(xì)的,學(xué)習(xí)一下
歡迎光臨 (http://m.zg4o1577.cn/bbs/) |
Powered by Discuz! X3.1 |
主站蜘蛛池模板:
999国产视频|
免费黄色小视频
|
六月丁香综合
|
黄色大毛片
|
色虎网站|
超碰97在线播放
|
午夜tv|
操小妹影院
|
午夜影院在线
|
免费一区二区
|
色天堂视频
|
蜜臀久久99精品久久久久宅男
|
欧美成人极品
|
色婷婷久久综合
|
精产国产伦理一二三区
|
国产精品视频免费在线观看
|
亚洲永久免费
|
国产一区二区三区在线观看视频
|
一区二区三区四区在线
|
福利视频免费
|
亚洲精品区
|
日韩视频在线观看免费
|
不卡的av在线
|
99视频免费在线观看
|
国产毛片在线
|
69精品人人人人
|
久久精品国产一区
|
精品视频国产
|
超碰免费在线
|
国产对白videos麻豆高潮
|
亚洲黄色三级
|
国产永久在线
|
成人免费激情视频
|
成人午夜网站
|
最新日韩av
|
中文字幕免费观看视频
|
成人毛片在线播放
|
亚洲精品字幕
|
999久久久久久久久6666
|
中文字幕在线日韩
|
国产欧美一区二区精品性色超碰
|