ice40+stm32 频率计-寒假一起练
ice40+stm32 频率计 以STM32产生PWM波,经过一阶低通滤波,与被测信号作比较,产生较为稳定的脉冲信号,在时间t内对被测信号的时钟周期N进行计数,然后求出单位时间内的时钟周期数,即为被测信号的频率。
标签
嵌入式系统
FPGA
Upton
更新2023-03-28
山东科技大学
380

 part1 硬件简介

本设计基于Lattice的ICE40UP5K FPGA和STM32G031 MCU,板载LPC11U35下载器,可以通过USB-C接口进行FPGA的配置,并通过虚拟串口通信配置STM32G031,支持在ICE40UP5K上对RISC-V软核的移植以及开源的FPGA开发工具链,板上RGB三色LED灯用于简单的调试,总计36个IO用于扩展使用,其中14个连接STM32G031 芯片,另外的22根连接ICE40UP5K FPGA芯片。

搭配电赛扩展板,帮助信号源、仪器仪表、控制以及信号处理类题目的训练。板上有通过两个16Pin的插座可以安装高速ADC(16Pin可再用模块/同时支持DIP和邮票孔)、高速DAC(16Pin可再用模块/支持DIP和邮票孔)、板上安装了高速比较器、姿态传感器、旋转编码器以及按键等。

 

 

 

part2 设计思路

FqWSY3qDwqXS6DxI29g5TFX4Q8Kk

利用板上的高速比较器和STM32的逻辑实现高速频率计和计数器的功能。以STM32输出PWM波,经过一阶低通滤波,与输入信号比较,产生稳定的脉冲信号,方便STM32捕获计算频率。

采用方法:  频率测量法

以STM32产生PWM波,经过一阶低通滤波,与被测信号作比较,产生较为稳定的脉冲信号,在时间t内对被测信号的时钟周期N进行计数,然后求出单位时间内的时钟周期数,即为被测信号的频率。

下面为配置图

时钟树倍频到64mhz

定时器采用外部计数器的方法

Fva1lbNEl6VtWwmU2kGXo71gSlAk

oled为软件spi驱动(配置省略,附件有ioc配置文件)

part3 代码简介

while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

    for (uint8_t i = 0; i < 15; i++)
    {

      HAL_TIM_Base_Start(&htim2); 
      HAL_TIM_Base_Start_IT(&htim2);

      HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);

      switch (TIM2_CAPTURE_STA)
      {
      case 0:
      {
        TIM2_TIMEOUT_COUNT = 0;
        __HAL_TIM_SET_COUNTER(&htim2, 0); 
        TIM2_CAPTURE_BUF[0] = 0;         
        TIM2_CAPTURE_BUF[1] = 0;
        TIM2_CAPTURE_BUF[2] = 0;
        TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING); 
        HAL_TIM_Base_Start_IT(&htim2);                           
        HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);              
        TIM2_CAPTURE_STA++;
        break;
      }

      case 4:
      {
        uint32_t high = TIM2_CAPTURE_BUF[1] - TIM2_CAPTURE_BUF[0];
        uint32_t cycle = TIM2_CAPTURE_BUF[2] - TIM2_CAPTURE_BUF[0];
        float frq = 1.0 / (((float)cycle) / 1000000.0);
        TIM2_CAPTURE_STA = 0;


        buf[i] = frq;
        break;
      }

      default:
        break;
      }
    }
	qsort(buf, 15, sizeof(float), cmpfunc);
	OLED_Clear1();
    SetCursor(0, 32);
     printf("%.1fHz\r\n",buf[7] );
    HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    HAL_Delay(50);
    OLED_Refresh();
  }

 

下面是外部定时器TIM2的配置函数

 

/* USER CODE BEGIN 1 */
__IO uint32_t TIM2_TIMEOUT_COUNT = 0;			///< 定时器2定时溢出计数
uint32_t TIM2_CAPTURE_BUF[3]   = {0, 0, 0};		///< 分别存储上升沿计数、下降沿计数、下个上升沿计数
__IO uint8_t TIM2_CAPTURE_STA = 0;			///< 状态标记

/**
 * 设置TIM2输入捕获极性
 * @param TIM_ICPolarity:
 *        TIM_INPUTCHANNELPOLARITY_RISING  :上升沿捕获
 *        TIM_INPUTCHANNELPOLARITY_FALLING :下降沿捕获
 *        TIM_INPUTCHANNELPOLARITY_BOTHEDGE:上升沿和下降沿都捕获
 */
void TIM2_SetCapturePolarity(uint32_t TIM_ICPolarity)
{
    htim2.Instance->CCER &= ~(TIM_CCER_CC2P | TIM_CCER_CC2NP);
    htim2.Instance->CCER |= (TIM_ICPolarity & (TIM_CCER_CC2P | TIM_CCER_CC2NP));
}

/// 定时器2时间溢出回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == htim2.Instance)
    {
        TIM2_TIMEOUT_COUNT++;										// 溢出次数计数
    }
}

///< 输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == htim2.Instance)
    {
        switch (TIM2_CAPTURE_STA)
        {
            case 1:
            {
//                printf("准备捕获下降沿...\r\n");
                TIM2_CAPTURE_BUF[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) + TIM2_TIMEOUT_COUNT * 0xFFFF;
                TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_FALLING);					// 设置为下降沿触发
                TIM2_CAPTURE_STA++;
                break;
            }
            case 2:
            {
//                printf("准备捕获下个上升沿...\r\n");
                TIM2_CAPTURE_BUF[1] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) + TIM2_TIMEOUT_COUNT * 0xFFFF;
                TIM2_SetCapturePolarity(TIM_INPUTCHANNELPOLARITY_RISING);					// 设置为上升沿触发
                TIM2_CAPTURE_STA++;
                break;
            }
            case 3:
            {
//                printf("捕获结束...\r\n");
//                printf("# end ----------------------------------------------------\r\n");
                TIM2_CAPTURE_BUF[2] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2) + TIM2_TIMEOUT_COUNT * 0xFFFF;
                HAL_TIM_IC_Stop_IT(htim, TIM_CHANNEL_2);									// 停止捕获
                HAL_TIM_Base_Stop_IT(&htim2);												// 停止定时器更新中断
                TIM2_CAPTURE_STA++;
                break;
            }
            default:
                break;
        }
    }
}

实际测试中发现由于比较器的误差太大,故使用多次测量的方法进行降噪,同时测量15次,存入数组,后排序,输出位于第7位的数组进行输出。

下面为测试环节

使用小脚丫fpga做的dds测试频率计

FlkVnWufr0gHcHUMGdWgEQLGK6Rz

同时验证dds

 

Fo1etK-9gGwBX-ltIkNrFQJNA8ZaFtDrzP5UDcH61NJcRY7SjjqVFoELFqIgTmCRh4Ntro3jnL6ZjGqPVzhhFh-3E_YKhIMeE7p9uuAw6lLJx-HkFtI1uPLIzUHUIzlr8CtKzV_3OSQhFuCShjFgR3tyNaN9oo2Urrrxr1LXFiljEBolCr7sWM2_TPZmRZzamcML

 

FqIgTmCRh4Ntro3jnL6ZjGqPVzhhFh-3E_YKhIMeE7p9uuAw6lLJx-Hk

 

下面使用信号发生器进行测试

 

pplUMW9.png

pplaRHK.png

pplahND.png

pplar9J.png pplaBh4.md.pngpplas39.md.pngpplawAU.pngppla0NF.pngppla6j1.md.pngpplagnx.md.pngppla2B6.pngpplaycR.png

 

 

part4 总结

排除信号源问题,发现是比较器输出上的问题,输出的频率是不准确的,需要滤波和计算,故存在一定的误差。

目前只测试了正弦波和三角波。

ps:未使用fpga,只使用了stm32和高速比较器

 

 

 

 

 
附件下载
LEDdemo.hex
LEDdemo (5).zip
团队介绍
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号