摘要:關(guān)于的塊不打算展開說,這里針對呼吸燈的詳細(xì)說明。描述定時器底層回調(diào)初始化參數(shù)無返回?zé)o描述定時器中斷處理函數(shù)參數(shù)無返回?zé)o呼吸燈注意由于產(chǎn)生中斷過快,反轉(zhuǎn)實現(xiàn)不了電平反轉(zhuǎn)上面代碼是中斷處理函數(shù),對呼吸燈的引腳電平反轉(zhuǎn)。
呼吸燈的實現(xiàn)可以通過控制燈的亮度連續(xù)變化,當(dāng)變化的頻率大于24幀時,肉眼看上去就會逐漸變暗,逐漸變亮。
PWM通過設(shè)置亮度在一段時間內(nèi)的占空比,亮的百分比多,人眼看到的就亮,反之就是暗。
關(guān)于PWM的塊不打算展開說,這里針對呼吸燈的PWM詳細(xì)說明。
/* * 描述 :呼吸燈PWM初始化 * 參數(shù) : * 無 * 返回 : * 無 */void bspBreathLedTIMInit(void){ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; g_breathled_tim_handle.Instance = TIM2; g_breathled_tim_handle.Init.Prescaler = 83; g_breathled_tim_handle.Init.CounterMode = TIM_COUNTERMODE_UP; g_breathled_tim_handle.Init.Period = (BREATHLED_PWM_VALUE - 1); g_breathled_tim_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; g_breathled_tim_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; if (HAL_TIM_Base_Init(&g_breathled_tim_handle) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&g_breathled_tim_handle, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&g_breathled_tim_handle) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&g_breathled_tim_handle, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&g_breathled_tim_handle, &sConfigOC, TIM_CHANNEL_4) != HAL_OK) { Error_Handler(); } GPIO_InitTypeDef GPIO_InitStruct; BREATHLED_GPIO_CLK_ENABLE(); /* TIM2 GPIO Configuration * PA3 ------> TIM2_CH4 */ GPIO_InitStruct.Pin = BREATHLED_GPIO_GREEN_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; HAL_GPIO_Init(BREATHLED_GPIO_TYPE, &GPIO_InitStruct); HAL_TIM_Base_Start_IT(&g_breathled_tim_handle);}
我這里使用了PA3引腳,定時器2做實驗。時鐘頻率是84MHz,Prescaler設(shè)置(84 - 1) = 83,Period這里設(shè)置是(10000 - 1) = 9999,所以定時器是 (83 + 1) * (9999 + 1) / 84000000 = 0.01s = 10ms一個周期。
這個頻率各位可以根據(jù)實際情況去計算,盡量設(shè)置成看上去平滑,而且對系統(tǒng)也不會造成產(chǎn)生過多中斷。
/* * 描述 :定時器底層回調(diào)初始化 * 參數(shù) : * 無 * 返回 : * 無 */void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim_base){ if (htim_base->Instance == TIM2) { __HAL_RCC_TIM2_CLK_ENABLE(); HAL_NVIC_SetPriority(TIM2_IRQn, 5, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); }}/* * 描述 :定時器中斷處理函數(shù) * 參數(shù) : * 無 * 返回 : * 無 */void TIM2_IRQHandler(void){ HAL_TIM_IRQHandler(&g_breathled_tim_handle); HAL_TIM_PeriodElapsedCallback(&g_breathled_tim_handle); }void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ /* USER CODE BEGIN Callback 0 */ /* USER CODE END Callback 0 */ if (htim->Instance == TIM11) { HAL_IncTick(); } //呼吸燈 else if (htim->Instance == TIM2) { //注意由于產(chǎn)生中斷過快,反轉(zhuǎn)實現(xiàn)不了 //LED電平反轉(zhuǎn) HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_3); } /* USER CODE BEGIN Callback 1 */ /* USER CODE END Callback 1 */}
上面代碼是中斷處理函數(shù),對呼吸燈的引腳電平反轉(zhuǎn)。是通過設(shè)置占空比的參數(shù),定時器自動觸發(fā)中斷后反轉(zhuǎn)電平。
//PWM設(shè)置的Period值#define BREATHLED_PWM_VALUE 10000//呼吸燈x軸變暗或變亮步數(shù)#define BREATHLED_X_DIVIDE 100//呼吸燈x軸總步數(shù)#define BREATHLED_X_TOTAL (BREATHLED_X_DIVIDE * 2)//呼吸燈y軸比例#define BREATHLED_Y_RATIO (BREATHLED_PWM_VALUE / BREATHLED_X_DIVIDE)//亮度變化頻率,也就是幀數(shù),單位毫秒#define BREATHLED_FRAMES_MS 10
一些宏定義,BREATHLED_PWM_VALUE值是上面PWM設(shè)置的Period值。
BREATHLED_X_DIVIDE是x軸,變暗或變亮?xí)r,x軸的步數(shù)。
BREATHLED_X_TOTAL是x軸變暗加上變亮一個周期的總步數(shù)。
BREATHLED_Y_RATIO是y軸比例。
BREATHLED_FRAMES_MS亮度變化頻率,注意這個值必須大于24幀,也就是小于40毫秒的時間,為了更加平滑,可以適量提高幀數(shù),這樣看起來呼吸燈更加流暢。
y = 10000時代表占空比100%,x軸為時間。
/* * 描述 :呼吸燈函數(shù),由x軸得出y軸值 * 參數(shù) : * [in] x x軸,時間 * 返回 : * y軸值,PWM值 */static unsigned int breathLedCurve(unsigned int x){ unsigned int y; if (x < BREATHLED_X_DIVIDE) { y = BREATHLED_Y_RATIO * x; } else { y = -BREATHLED_Y_RATIO * (x - BREATHLED_X_TOTAL); } return y;}/* * 描述 :呼吸燈過程 * 參數(shù) : * 無 * 返回 : * 無 */void breathLedProgress(void){ static unsigned int time_x = 0; unsigned int pwm_value_y = 0; while (1) { time_x = (time_x + 1) % BREATHLED_X_TOTAL; pwm_value_y = breathLedCurve(time_x); //修改占空比 __HAL_TIM_SetCompare(&g_breathled_tim_handle, TIM_CHANNEL_4, pwm_value_y); sysDelay(BREATHLED_FRAMES_MS); if (time_x % BREATHLED_X_DIVIDE == 0) { sysDelay(500); } }}
實現(xiàn)方式可以參考上面的,但是人眼感受的卻不是線性的,是由于在燈光微亮區(qū),很小的光通量改變也讓人眼感到光通量變化很大,而在光通量比較大的區(qū)域,很大的光通量跳躍,人眼感覺到的光通量變化不大,簡單理解為,人眼對亮度暗的比較敏感,而對亮度量的不敏感。
所以你嘗試后發(fā)現(xiàn),當(dāng)由亮變暗時感覺時間長,由暗變亮?xí)r時間短,會有突然變亮的感覺。這個曲線是有缺陷的。
由上圖可知,當(dāng)亮度由暗變亮?xí)r,程序的呼吸燈曲線需要如同圖3。
為了方便我這里使用一元二次曲線,有條件的可以使用sin函數(shù),但是效果或許看起來會差不多。但是sin函數(shù)計算量會比一元二次方程大的多,所以衡量之下,選擇通過一元二次曲線來實現(xiàn)。
通過這個曲線,你可能感覺到和線性折線差不多的效果。所以還需要降低由暗變亮?xí)r的亮度變化頻率,即可讓人眼看上去平滑。
有需要的可以移步呼吸燈曲線代碼下載。或者有能力的可以自行參考上面代碼,實現(xiàn)該曲線。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/118972.html
摘要:利用可視化界面來進行的相關(guān)配置,所以時鐘滴答定時器串口等就不用根據(jù)數(shù)據(jù)手冊去操作標(biāo)準(zhǔn)庫甚至是寄存器了,可以通過軟件直接生成。 使用STM32CubeMX初始化ST...
摘要:總線掛載的外設(shè)有等。外設(shè)地址映射片上外設(shè)區(qū)分為三條總線,根據(jù)外設(shè)速度的不同,不同總線掛載著不同的外設(shè),掛載低速外設(shè),和掛載高速外設(shè)。 第二章 STM32資源介紹 2...
摘要:呼吸燈也可以通過加層罩,通過設(shè)置層罩透明度來實現(xiàn)亮度動畫 呼吸燈 /*也可以通過加層罩,通過設(shè)置層罩透明度來實現(xiàn)亮度動畫*/ body{ background-color: black; } div{ margin: 0 auto; margin-top: 200px; width: 300p...
摘要:開關(guān)旋鈕電位器的實驗視頻已經(jīng)購買開發(fā)版的同學(xué)開始上課來一場緊張刺激的之旅吧前言開發(fā)工具的下載安裝使用都很簡單我這里就不贅述了附上官方的說明跟著步驟來十分鐘搞定相關(guān)連接下載官方為什么成為開發(fā)函數(shù) ...
摘要:初始化引腳和基礎(chǔ)設(shè)置利用宏定義定義引腳高或者低全部引腳為高原理圖是低平點亮高電平滅利用宏定義設(shè)置時間關(guān)閉燈流水燈延時時間為的值先關(guān)閉全部燈循環(huán)流水燈 /* US...
閱讀 1761·2021-10-12 10:12
閱讀 2530·2021-09-29 09:42
閱讀 2711·2021-09-03 10:28
閱讀 2249·2019-08-30 15:54
閱讀 1153·2019-08-30 15:53
閱讀 1388·2019-08-30 11:26
閱讀 3356·2019-08-30 11:02
閱讀 2133·2019-08-30 11:02