704|5

174

帖子

0

资源

一粒金砂(中级)

【STM32F769Discovery开发板试用】串口空闲中断不定长接收&PWM输出方波

本帖最后由 donatello1996 于 2020-8-10 12:01 编辑

       串口空闲中断和PWM方波输出都是实际产品项目中非常常用的功能,串口空闲中断的好处在于可以使用不轮询方式,不占用CPU资源的前提下进行不定长串口字符串接收,因为触发方式是使用中断。使用空闲中断实现不定长接收的方式非常简单,只需要两点,一个是开启空闲中断,一个是开启接收DMA,这边我使用开发板的Arduino接口上面的串口6(USART6)来进行:

33.jpg

接收DMA初始化使用CubeMX自动一键生成:

34.jpg 35.jpg

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);
}
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;
	}
}

主循环中使用轮询处理代码处理空闲中断中接收到的数据,这里是只有触发了空闲中断才会处理数据并重新开启DMA,所以是不会占用CPU轮询资源的:

#define BUFFERSIZE 255
unsigned char rx6_buf[BUFFERSIZE],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);
	}
}

将串口6接入一个定时打印数值的传感器,就可以采集数据了,不过值得一提的是,串口空闲中断本质上仍是中断,如果空闲中断触发次数过于频繁,会严重影响CPU正常轮询工作,所以选用的串口传感器不能是每一帧发送间隔太短,频繁触发空闲中断的传感器。

然后是PWM,这里我使用Arduino接口的PF6即TIM10的通道1,可以直接参考原子代码来修改进行初始化:

36.jpg

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; 
}

输出效果:

IMG_20200809_165156.jpg

这里可以提一下TIM10的两个初始化参数,一个是重装载值,一个是分频值,重装载值的作用是设置一个PWM比较阈值,比如256,在0~256范围内占空比是0%~100%变化,而分频值就是PWM输出方波的频率,分频值越小,PWM频率越高,输出一个方波周期的时间就越短,这里我设置TIM10分频值为1,PWM波的输出间隔达到了1us级别,即1MHz,不过这样仍然算是频率较低的,之后我再继续探讨看看怎么输出更高频率的方波。

其它参数中,向上计数模式即为增量模式,即TIM10的计数器越计越多,模式为PWM1即占空比数值越大,一个周期内的低电平时间越长。


回复

174

帖子

0

资源

一粒金砂(中级)

初步推测,能输出更高频率PWM方波跟定时器本身有关系,试下换TIM2 TIM3这些更常用的定时器,看看能能不能输出更高频率的方波,做这个PWM实验的一大难题是开发板引出的GPIO引脚极其稀少,大部分都被FMC和LTDC两个接口的外设占用掉了,Arduino接口上引出的那些引脚每一个都是非常宝贵的资源。


回复

2552

帖子

1

资源

五彩晶圆(初级)

你这是想搞到100分啊?

点评

哈哈道长见笑了,反正这段时间都有在玩这板,写一下心得罢了  详情 回复 发表于 2020-8-11 13:40
个人签名人已离开,无事别找,找也找不到。

回复

174

帖子

0

资源

一粒金砂(中级)

freebsder 发表于 2020-8-10 18:59 你这是想搞到100分啊?

哈哈道长见笑了,反正这段时间都有在玩这板,写一下心得罢了

点评

挺好啊,写的很详细,幸好我转手了,要不和你比就相形见绌了。  详情 回复 发表于 2020-8-11 20:54

回复

2552

帖子

1

资源

五彩晶圆(初级)

donatello1996 发表于 2020-8-11 13:40 哈哈道长见笑了,反正这段时间都有在玩这板,写一下心得罢了

挺好啊,写的很详细,幸好我转手了,要不和你比就相形见绌了。

点评

谢谢道长,道长过奖了  详情 回复 发表于 2020-8-11 21:27
个人签名人已离开,无事别找,找也找不到。

回复

174

帖子

0

资源

一粒金砂(中级)

freebsder 发表于 2020-8-11 20:54 挺好啊,写的很详细,幸好我转手了,要不和你比就相形见绌了。

谢谢道长,道长过奖了


回复
您需要登录后才可以回帖 登录 | 注册

关闭
站长推荐上一条 1/7 下一条

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2020 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表