當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀] 該實驗采用W5500開發(fā)板通過上位機(jī)向開發(fā)板發(fā)送命令來控制外接燈帶的亮度;主要的過程如下:1實驗?zāi)康纳衔粰C(jī)通過串口發(fā)送格式為:“redbrightness,greenbrightness,bluebrightness”的字符串到MCU。MCU將

該實驗采用W5500開發(fā)板通過上位機(jī)向開發(fā)板發(fā)送命令來控制外接燈帶的亮度;主要的過程如下:

1實驗?zāi)康?p>上位機(jī)通過串口發(fā)送格式為:“redbrightness,greenbrightness,bluebrightness”的字符串到MCU。MCU將數(shù)字轉(zhuǎn)化成相應(yīng)的亮度。

2實驗總體設(shè)計

實驗主要分兩個部分:PWM配置以及串口通信配置。整個實驗的難點在于ASCII碼轉(zhuǎn)換為數(shù)字的過程。

3PWM產(chǎn)生原理

通用定時器可以利用GPIO引腳進(jìn)行脈沖輸出。要使STM32的通用定時器TIMx產(chǎn)生PWM輸出,需要用到3個寄存器。分別是:捕獲/比較模式寄存器(TIMx_CCMR1/2)、捕獲/比較使能寄存器(TIMx_CCER)、捕獲/比較寄存器(TIMx_CCR1~4)。(注意,還有個TIMx的ARR寄存器是用來控制pwm的輸出頻率)。

對于捕獲/比較模式寄存器(TIMx_CCMR1/2),該寄存器總共有2個,TIMx _CCMR1和TIMx _CCMR2。TIMx_CCMR1控制CH1和2,而TIMx_CCMR2控制CH3和4。其次是捕獲/比較使能寄存器(TIMx_CCER),該寄存器控制著各個輸入輸出通道的開關(guān)。

最后是捕獲/比較寄存器(TIMx_CCR1~4),該寄存器總共有4個,對應(yīng)4個輸通道CH1~4。4個寄存器作用相近,都是用來設(shè)置pwm的占空比的。例如,若配置脈沖計數(shù)器TIMx_CNT為向上計數(shù),而重載寄存器TIMx_ARR被配置為N,即TIMx_CNT的當(dāng)前計數(shù)值數(shù)值X在TIMxCLK時鐘源的驅(qū)動下不斷累加,當(dāng)TIMx_CNT的數(shù)值X大于N時,會重置TIMx_CNT數(shù)值為0重新計數(shù)。而在TIMxCNT計數(shù)的同時,TIMxCNT的計數(shù)值X會與比較寄存器TIMx_CCR預(yù)先存儲了的數(shù)值A(chǔ)進(jìn)行比較,當(dāng)脈沖計數(shù)器TIMx_CNT的數(shù)值X小于比較寄存器TIMx_CCR的值A(chǔ)時,輸出高電平(或低電平),相反地,當(dāng)脈沖計數(shù)器的數(shù)值X大于或等于比較寄存器的值A(chǔ)時,輸出低電平(或高電平)。如此循環(huán),得到的輸出脈沖周期就為重載寄存器TIMx_ARR存儲的數(shù)值(N+1)乘以觸發(fā)脈沖的時鐘周期,其脈沖寬度則為比較寄存器TIMx_CCR的值A(chǔ)乘以觸發(fā)脈沖的時鐘周期,即輸出PWM的占空比為A/(N+1)。

4PWM配置步驟4.1配置GPIO

void LED_Config(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE);//開啟復(fù)用時鐘

GPIO_InitStructure.GPIO_Pin = LED_RED| LED_BLUE | LED_GREEN;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOC, &GPIO_InitStructure);

GPIO_SetBits(GPIOC, LED_RED | LED_BLUE | LED_GREEN);

}

4.2 配置定時器

void TIMER_Config(void)

{

TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);

TIM_BaseInitStructure.TIM_Period = 255;

TIM_BaseInitStructure.TIM_Prescaler = 0;

TIM_BaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_BaseInitStructure);

TIM_ARRPreloadConfig(TIM3, ENABLE);

TIM_Cmd(TIM3, ENABLE);

}

4.3配置PWM

void PWM_Config(void)

{

TIM_OCInitTypeDef TIM_OCInitStructure;

TIM_OCStructInit(&TIM_OCInitStructure);

TIM_OCInitStructure.TIM_Pulse = 0;

TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1; //選擇模式1

TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low //極性為高電平有效

TIM_OC2Init(TIM3, &TIM_OCInitStructure);

TIM_OC3Init(TIM3, &TIM_OCInitStructure);

TIM_OC4Init(TIM3, &TIM_OCInitStructure);

TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);

TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);

TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);

TIM_CtrlPWMOutputs(TIM3,ENABLE);

}

4.4小結(jié)

PWM模式1:

在向上計數(shù)時,一旦TIMx_CNTTIMx_CCR1時通道1為無效電平(OC1REF=0),否則為有效電平(OC1REF=1)。

PWM模式2:

在向上計數(shù)時,一旦TIMx_CNTTIMx_CCR1時通道1為有效電平,否則為無效電平。

同時輸出的有效點評還與極性配置有關(guān):

TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

此配置是高電平為有效電平,反之亦然。

5 UART配置步驟5.1 配置UART1以及對應(yīng)的GPIO

void Usart_Config(uint32_t BaudRate)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitStructure.USART_BaudRate = BaudRate;

USART_InitStructure.USART_WordLength = USART_WordLength_8b;

USART_InitStructure.USART_StopBits = USART_StopBits_1;

USART_InitStructure.USART_Parity = USART_Parity_No;

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_Init(USART_PC, &USART_InitStructure);

USART_ITConfig(USART_PC, USART_IT_RXNE, ENABLE); //開啟串口接收中斷

USART_ITConfig(USART_PC, USART_IT_IDLE, ENABLE); //開啟串口接收中斷

USART_Cmd(USART_PC, ENABLE);

}

5.2配置中斷

void NVIC_Configuration(void)

{

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

}

5.3中斷函數(shù)

void USART1_IRQHandler(void)

{

uint8_t clear = clear;

if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)

{

USART_ClearITPendingBit(USART1, USART_IT_RXNE);

RxBuffer[RxCounter++] = USART_ReceiveData(USART1);

}

else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)

{

clear = USART1->SR;

clear = USART1->DR; //先讀SR再讀DR,為了清除IDLE中斷

RxNumber = RxCounter;

RxCounter = 0;//計數(shù)清零

IDLE_Flag = 1;//標(biāo)記接收到一幀的數(shù)據(jù)

}

}

5.4小結(jié)

STM32單片機(jī)可以實現(xiàn)接收不定長度字節(jié)數(shù)據(jù)。由于STM32單片機(jī)帶IDLE中斷,利用這個中斷,可以接收不定長字節(jié)的數(shù)據(jù)。由于STM32屬于ARM單片機(jī),所以這篇文章的方法也適合其他的ARM單片機(jī)。

IDLE就是串口收到一幀數(shù)據(jù)后,發(fā)生的中斷。比如說給單片機(jī)一次發(fā)來1個字節(jié),或者一次發(fā)來8個字節(jié),這些一次發(fā)來的數(shù)據(jù),就稱為一幀數(shù)據(jù),也可以叫做一包數(shù)據(jù)。一幀數(shù)據(jù)結(jié)束后,就會產(chǎn)生IDLE中斷。這個中斷十分有用,可以省去了好多判斷的麻煩。

6 ASCII碼轉(zhuǎn)換為數(shù)字6.1實現(xiàn)步驟:

while(RxBuffer[i] != ','){ i++; len++;}//如果不為','長度加1

for(j=i-len; j

value = RxBuffer[j]&0x0f; //將ascii碼轉(zhuǎn)換為數(shù)字

pwm_red += value * Power(len-1);

len--;

}

i++;

len = 0;

while(RxBuffer[i] != ','){ i++; len++;}

for(j=i-len; j

value = RxBuffer[j]&0x0f; //將ascii碼轉(zhuǎn)換為數(shù)字

pwm_green += value * Power(len-1);

len--;

}

i++;

len = 0;

while(RxBuffer[i] != '