【STM32F769Discovery开发板试用】串口空闲中断不定长接收&PWM输出方波
本帖最后由 donatello1996 于 2020-8-10 12:01 编辑<p> 串口空闲中断和PWM方波输出都是实际产品项目中非常常用的功能,串口空闲中断的好处在于可以使用不轮询方式,不占用CPU资源的前提下进行不定长串口字符串接收,因为触发方式是使用中断。使用空闲中断实现不定长接收的方式非常简单,只需要两点,一个是开启空闲中断,一个是开启接收DMA,这边我使用开发板的Arduino接口上面的串口6(USART6)来进行:</p>
<p></p>
<p>接收DMA初始化使用CubeMX自动一键生成:</p>
<p></p>
<pre>
<code>UART_HandleTypeDef huart6;
DMA_HandleTypeDef hdma_usart6_rx;
void UART6_Init(int baud)
{
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_USART6_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF8_USART6;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
huart6.Instance = USART6;
huart6.Init.BaudRate = baud;
huart6.Init.WordLength = UART_WORDLENGTH_8B;
huart6.Init.StopBits = UART_STOPBITS_1;
huart6.Init.Parity = UART_PARITY_NONE;
huart6.Init.Mode = UART_MODE_TX_RX;
huart6.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart6.Init.OverSampling = UART_OVERSAMPLING_16;
huart6.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart6.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart6);
hdma_usart6_rx.Instance = DMA2_Stream1;
hdma_usart6_rx.Init.Channel = DMA_CHANNEL_5;
hdma_usart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_usart6_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_usart6_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_usart6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_usart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_usart6_rx.Init.Mode = DMA_CIRCULAR;
hdma_usart6_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_usart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_usart6_rx);
__HAL_LINKDMA(&huart6,hdmarx,hdma_usart6_rx);
__HAL_UART_ENABLE_IT(&huart6,UART_IT_IDLE);
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
HAL_NVIC_SetPriority(USART6_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART6_IRQn);
}</code></pre>
<pre>
<code>void USART6_IRQHandler()
{
int temp;
if(__HAL_UART_GET_FLAG(&huart6, UART_FLAG_IDLE))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart6);
HAL_UART_DMAStop(&huart6);
temp=__HAL_DMA_GET_COUNTER(&hdma_usart6_rx);
rx6_len=BUFFERSIZE-temp;
uart6_recv_end_flag=1;
}
}</code></pre>
<p>主循环中使用轮询处理代码处理空闲中断中接收到的数据,这里是只有触发了空闲中断才会处理数据并重新开启DMA,所以是不会占用CPU轮询资源的:</p>
<pre>
<code>#define BUFFERSIZE 255
unsigned char rx6_buf,rx6_len=0,uart6_recv_end_flag;
void UART6_DMA_Get()
{
if(uart6_recv_end_flag==1)
{
uart6_recv_end_flag=0;
printf("%s %d\n",rx6_buf,rx6_len);
HAL_UART_Receive_DMA(&huart6, (unsigned char*)rx6_buf, BUFFERSIZE);
}
}
</code></pre>
<p>将串口6接入一个定时打印数值的传感器,就可以采集数据了,不过值得一提的是,串口空闲中断本质上仍是中断,如果空闲中断触发次数过于频繁,会严重影响CPU正常轮询工作,所以选用的串口传感器不能是每一帧发送间隔太短,频繁触发空闲中断的传感器。</p>
<p>然后是PWM,这里我使用Arduino接口的PF6即TIM10的通道1,可以直接参考原子代码来修改进行初始化:</p>
<p></p>
<pre>
<code>TIM_HandleTypeDef TIM10_Handler;
TIM_OC_InitTypeDef TIM10_CH1Handler;
void TIM10_PWM_Init(int arr,int psc)
{
__HAL_RCC_TIM10_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Initure;
GPIO_Initure.Pin=GPIO_PIN_6;
GPIO_Initure.Mode=GPIO_MODE_AF_PP;
GPIO_Initure.Pull=GPIO_PULLUP;
GPIO_Initure.Speed=GPIO_SPEED_HIGH;
GPIO_Initure.Alternate=GPIO_AF3_TIM10;
HAL_GPIO_Init(GPIOF,&GPIO_Initure);
TIM10_Handler.Instance=TIM10;
TIM10_Handler.Init.Prescaler=psc;
TIM10_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;
TIM10_Handler.Init.Period=arr;
TIM10_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&TIM10_Handler);
TIM10_CH1Handler.OCMode=TIM_OCMODE_PWM1;
//模式选择PWM1
TIM10_CH1Handler.Pulse=arr/2;
//设置比较值,此值用来确定占空比,
//默认比较值为自动重装载值的一半,即占空比为50%
TIM10_CH1Handler.OCPolarity=TIM_OCPOLARITY_LOW;
HAL_TIM_PWM_ConfigChannel(&TIM10_Handler,&TIM10_CH1Handler,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&TIM10_Handler,TIM_CHANNEL_1);
}
void TIM_SetTIM10Compare1(int compare)
{
TIM10->CCR1=compare;
}</code></pre>
<p>输出效果:</p>
<p></p>
<p>这里可以提一下TIM10的两个初始化参数,一个是重装载值,一个是分频值,重装载值的作用是设置一个PWM比较阈值,比如256,在0~256范围内占空比是0%~100%变化,而分频值就是PWM输出方波的频率,分频值越小,PWM频率越高,输出一个方波周期的时间就越短,这里我设置TIM10分频值为1,PWM波的输出间隔达到了1us级别,即1MHz,不过这样仍然算是频率较低的,之后我再继续探讨看看怎么输出更高频率的方波。</p>
<p>其它参数中,向上计数模式即为增量模式,即TIM10的计数器越计越多,模式为PWM1即占空比数值越大,一个周期内的低电平时间越长。</p>
<p>初步推测,能输出更高频率PWM方波跟定时器本身有关系,试下换TIM2 TIM3这些更常用的定时器,看看能能不能输出更高频率的方波,做这个PWM实验的一大难题是开发板引出的GPIO引脚极其稀少,大部分都被FMC和LTDC两个接口的外设占用掉了,Arduino接口上引出的那些引脚每一个都是非常宝贵的资源。</p>
<p>你这是想搞到100分啊?</p>
freebsder 发表于 2020-8-10 18:59
你这是想搞到100分啊?
<p>哈哈道长见笑了,反正这段时间都有在玩这板,写一下心得罢了</p>
donatello1996 发表于 2020-8-11 13:40
哈哈道长见笑了,反正这段时间都有在玩这板,写一下心得罢了
<p>挺好啊,写的很详细,幸好我转手了,要不和你比就相形见绌了。</p>
freebsder 发表于 2020-8-11 20:54
挺好啊,写的很详细,幸好我转手了,要不和你比就相形见绌了。
<p>谢谢道长,道长过奖了</p>
页:
[1]