annysky2012 发表于 2021-9-22 17:37

【基于NUCLEO-F746ZG电机开发应用】7.程序框架-两个重要中断

<div class='showpostmsg'><p><span style="font-size:20px;">&nbsp; &nbsp; &nbsp; 上个帖子<a href="https://bbs.eeworld.com.cn/thread-1179648-1-1.html" target="_blank">【基于NUCLEO-F746ZG电机开发应用】6.程序框架</a>中说到系统在初始化完成后,进入到主循环中,主函数中没有任何任务执行,所有的任务都在中断中。主要在两个中断中:Systick中断和ADC中断。Systick中断执行安全任务和中频任务,ADC中断主要执行高频任务。本贴将详细介绍一下:</span></p>

<p><span style="font-size:20px;"><strong>1.Systick中断</strong></span></p>

<p><span style="font-size:20px;">&nbsp; &nbsp; &nbsp; Systick系统定时器是属于CM7内核中的一个外设,内嵌在NVIC中。系统定时器是一个24bit的向下递减的计数器,计数器每计数一次的时间为1/SYSCLK。当重装载数值寄存器的值递减到0的时候,系统定时器就产生一次中断,以此循环往复。因为SysTick是属于CM7内核的外设,所以所有基于CM7内核的单片机都具有这个系统定时器,使得软件在CM7单片机中可以很容易的移植。系统定时器专用于实时操作系统,用于产生时基,维持操作系统的心跳。</span></p>

<p><span style="font-size:20px;">&nbsp; &nbsp; &nbsp; 本程序中Systick中断默认为1ms的定时,其中安全任务执行在这个中断中,中频任务(速度环)也执行在这个中断中。</span></p>

<p><span style="font-size:20px;">Systick中断初始化代码如下:</span></p>

<pre>
<code class="language-cpp">__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
/* Configure the SysTick to have interrupt in 1ms time basis*/
if (HAL_SYSTICK_Config(SystemCoreClock / (1000U / uwTickFreq)) &gt; 0U)
{
    return HAL_ERROR;
}

/* Configure the SysTick IRQ priority */
if (TickPriority &lt; (1UL &lt;&lt; __NVIC_PRIO_BITS))
{
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
}
else
{
    return HAL_ERROR;
}

/* Return function status */
return HAL_OK;
}</code></pre>

<p><span style="font-size:20px;">中断函数:</span></p>

<pre>
<code class="language-cpp">void SysTick_Handler(void)
{
    MC_RunMotorControlTasks();
}</code></pre>

<p><span style="font-size:20px;">其中MC_RunMotorControlTasks()函数中,执行的是安全任务和中频任务:</span></p>

<pre>
<code class="language-cpp">__weak void MC_RunMotorControlTasks(void)
{
if ( bMCBootCompleted ) {
    /* ** Medium Frequency Tasks ** */
    MC_Scheduler(); //中频任务

    /* Safety task is run after Medium Frequency task so that
   * it can overcome actions they initiated if needed. */
    TSK_SafetyTask(); //安全任务

    /* ** User Interface Task ** */
    UI_Scheduler();//用户界面任务
}
}</code></pre>

<p><span style="font-size:20px;"><strong>2.</strong>ADC中断</span></p>

<p><span style="font-size:20px;">ADC中断完成高频任务,ADC采样开始由TIM1硬件触发。在中断中执行&nbsp; FOC坐标变换 , SVPWM的执行 和&nbsp;TIM1的PWM占空比调整输出。</span></p>

<p><span style="font-size:20px;">本程序中使用的是ADC1,完成对电流、母线电压、温度的采集。主要流程如下:</span></p>

<p><span style="font-size:20px;">ADC1初始化代码如下:</span></p>

<pre>
<code class="language-cpp">static void MX_ADC1_Init(void)
{

/* USER CODE BEGIN ADC1_Init 0 */

/* USER CODE END ADC1_Init 0 */

ADC_InjectionConfTypeDef sConfigInjected = {0};
ADC_ChannelConfTypeDef sConfig = {0};

/* USER CODE BEGIN ADC1_Init 1 */

/* USER CODE END ADC1_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //ADC1时钟4分频
hadc1.Init.Resolution = ADC_RESOLUTION_12B; //分辨率为12位
hadc1.Init.ScanConvMode = ADC_SCAN_ENABLE; //扫描模式开启
hadc1.Init.ContinuousConvMode = DISABLE; //连续采样模式关闭
hadc1.Init.DiscontinuousConvMode = DISABLE;//非连续采样模式关闭
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //禁止触发检测,使用软件触发
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_LEFT; //数据左对齐
hadc1.Init.NbrOfConversion = 2; //配置位2通道
hadc1.Init.DMAContinuousRequests = DISABLE; //关闭DMA传输数据
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;//使能EOC标志位
if (HAL_ADC_Init(&amp;hadc1) != HAL_OK)
{
    Error_Handler();
}
/** Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_0; //ADC1通道0
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_1;
sConfigInjected.InjectedNbrOfConversion = 2;
sConfigInjected.InjectedSamplingTime = ADC_SAMPLETIME_15CYCLES;
sConfigInjected.ExternalTrigInjecConvEdge = ADC_EXTERNALTRIGINJECCONVEDGE_RISING;
sConfigInjected.ExternalTrigInjecConv = ADC_EXTERNALTRIGINJECCONV_T1_CC4;
sConfigInjected.AutoInjectedConv = DISABLE;
sConfigInjected.InjectedDiscontinuousConvMode = ENABLE;
sConfigInjected.InjectedOffset = 0;
if (HAL_ADCEx_InjectedConfigChannel(&amp;hadc1, &amp;sConfigInjected) != HAL_OK)
{
    Error_Handler();
}
/** Configures for the selected ADC injected channel its corresponding rank in the sequencer and its sample time
*/
sConfigInjected.InjectedChannel = ADC_CHANNEL_11;
sConfigInjected.InjectedRank = ADC_INJECTED_RANK_2;
if (HAL_ADCEx_InjectedConfigChannel(&amp;hadc1, &amp;sConfigInjected) != HAL_OK)
{
    Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_28CYCLES;
sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&amp;hadc1, &amp;sConfig) != HAL_OK)
{
    Error_Handler();
}
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_12;
sConfig.Rank = ADC_REGULAR_RANK_2;
sConfig.Offset = 0;

if (HAL_ADC_ConfigChannel(&amp;hadc1, &amp;sConfig) != HAL_OK)
{
    Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */

/* USER CODE END ADC1_Init 2 */

}</code></pre>

<p><span style="font-size:20px;">ADC中断函数:</span></p>

<pre>
<code class="language-cpp">void ADC_IRQHandler(void)
{
/* USER CODE BEGIN ADC_IRQn 0 */

/* USER CODE END ADC_IRQn 0 */
if ( LL_ADC_IsActiveFlag_JEOS( ADC1 ) )//检查ADC转化标志
{
    LL_ADC_ClearFlag_JEOS( ADC1 );//清除标志
}

// Highfrequency task Single or M1
UI_DACUpdate(TSK_HighFrequencyTask()); //高频任务
/* USER CODE BEGIN ADC_IRQn 1 */

/* USER CODE END ADC_IRQn 1 */
}</code></pre>

<p><span style="font-size:20px;">从程序中可以看出,ADC中就只有一个任务,高频任务。为什么要把高频任务放在这里,是因为ADC要及时准确把电流电压的值采集完成后,给到FOC进行计算,然后将计算的值通过定时器TIM1转化为输出波形,使电机运行起来。</span></p>

<p>&nbsp;</p>
</div><script>                                var loginstr = '<div class="locked">查看精华帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                               
                                if(parseInt(discuz_uid)==0){
                                                                                        (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                }
</script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

Jacktang 发表于 2021-9-23 07:09

<p>楼主把Systick中断和ADC中断说的很清楚了</p>

annysky2012 发表于 2021-9-23 09:23

Jacktang 发表于 2021-9-23 07:09
楼主把Systick中断和ADC中断说的很清楚了

<p>谢谢,我也是一边学习一边分享。</p>

annysky2012 发表于 2021-9-23 09:23

Jacktang 发表于 2021-9-23 07:09
楼主把Systick中断和ADC中断说的很清楚了

<p>有什么不对的及时指正</p>

ssz1982 发表于 2023-11-13 14:27

<p>很好很好,谢谢楼主分享,学习了,赞赞赞赞赞赞赞赞赞赞赞赞赞赞</p>
页: [1]
查看完整版本: 【基于NUCLEO-F746ZG电机开发应用】7.程序框架-两个重要中断