1147.Sam数

1147.Sam数

时间限制:1000MS内存限制:128000KB

题目描述

   小G最近发现了一种非常有趣的数,他将这种数称之为Sam数。Sam数具有以下特征:相邻两位的数字之差不超过2。小G还将Sam数按位数进行了分类,他将一个k位Sam数称之为k阶Sam数。但不幸的是小G发现他数不清第k阶的Sam数一共有多少个,这个时候机智的他想到了向你求助。
 

输入

第一行为一个整数k,含义见题面。

输出

一行一个整数ans,表示k阶的Sam数的个数。
由于第k阶Sam数非常多,你只需要输出ans mod 1,000,000,007。

输入样例复制

输出样例复制

867

说明

【数据规模和约定】 对于30%的数据,1 ≤ k ≤ 6。 对于60%的数据,1 ≤ k ≤ 1000。 对于100%的数据,1 ≤ k ≤ 1000000。

 

 

题意:

    在k位数中,满足相邻俩位之差不过2;例如,1234,可以

1357,可以,5357,可以、531-1,不行;

有一点很坑:k=1时,答案是10;

解法:

啧啧,似乎是DP,看到这一题我第一想法是打表,

先讲打表:

   因为数30 percent 数据只有6位,所以说开另一个程序,用6个for枚举6位数得到结果,就在程序中直接输出。

简单易懂对不?

另一种DP:

    f[i][k]=f[i][k]+f[i-1][j];

i表示i位数,k表示以K结尾。J是一个FOR,枚举能放在最后一位的数。

记住初值为1;

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

using namespace std;

int n,m=1000000007,f[1000005][10],ans;
int main()
{
    
    cin>>n;
    if (n==1)
    {
        cout<<10;
        return 0;
    }
    for (int i=0;i<=9;i++) f[1][i]=1;
    for (int i=2;i<=n;i++)
      for (int j=0;j<=9;j++)
        for (int k=max(0,j-2);k<=min(9,j+2);k++)
          {
              f[i][j]=(long long)(f[i][j]+f[i-1][k])%m; 
          }
    for (int i=1;i<=9;i++)
    {
        ans=(long long)(f[n][i]+ans)%m;
    }
    cout<<ans;
}

    

 

在DC-AC单相全桥逆变电路中,使用stm32f103RCT6(DMA没有自带双缓冲模式?),软件部分,SPWM.c中我采用外部程序生成正弦表的1600个据点,(由于是中央对齐模式2,使用CC1触发DMA,故每个TIM1周期更新两个CCR据值,那么一个正弦波周期就是800个据点)通过TIM1的中央对齐模式2(ARR=1800-1,PSC=1-1,时序:0-->ARR-->0),每个TIM1周期为50us,每个TIM1周期更新两次CCR(向上计时CNT=CCR_A和向下计CNT=CCR_B时),使用TIM1_CC1触发DMA1的通道二将正弦表中的据依次搬运到TIM1_CCR1中完成SPWM的生成,我只需要用到一路主路PWM和互补PWM(即CH1和CH1N,因为我使用的驱动使IR2104,它只有一个输入端IN,两片IR2104,一片输入CH1另一片输入CH1N,它就是这么使用的)。ADC.c中打算采用TIM1_CC2触发ADC(同样是每个TIM1周期会采到两个样点,因为时序:0-->ARR-->0过程中会触发两次CC2)(双ADC同步规则分别采电压和电流)+DMA搬运进uint32_t组ADC_Dual_Value[Buffersize]中(这里Buffersize为1600,前800个据点是采到的一个完整正弦周期的据点,后800个点也是采到的完整的正弦周期的据点,我打算使用滑动窗口计算Rms而不是等待采完一整个正弦周期20ms才能计算一次Rms送入pid,由于据量太大,每个周期虽然实际采了800个点,但是我实际只取100个点(800个点里每8个据取1个),但是我一旦在TIM3触发的定时中断里执行Control_Loop()时,OLED就会黑屏不显示(使用的0.96寸4针脚(VCC、GND、SCL(PB8)、SDA(PB9))OLED显示屏,),但是注释掉TIM3_Init()时就恢复正常,应该时计算量太大了影响到OLED通信了?我该怎么办?或者换个思路使用一个定时器定时中断专门在中断里显示OLED刷新和显示的部分?代码如下,帮我分析分析,谢谢: Main.c:#include "stm32f10x.h" // Device header #include "Delay.h" #include "MYDAC.h" #include "ADC_DMA.h" #include "OLED.h" #include "OLED_Data.h" #include "PID.h" #include "SPWM.h" #include "Serial.h" uint8_t temp = 0; uint16_t Sam_Vol,Sam_Cur,vol_DAC; int main(void) //PA8输出主PWM PB13输出互补PWM PB0采电压 PB1采电流 { OLED_Init(); Timer3_Init(); TIM4_Init(); ADC_DMAInit(); SPWM_BDTR_Init(); //PID_Init(0.15,0.01,0,0,0,0); //Serial_DMA_Init(); OLED_ShowString(0,0,"电压值:",OLED_8X16); OLED_ShowString(0,16,"ADC电压:",OLED_8X16); OLED_ShowString(0,32,"输出电流:",OLED_8X16); OLED_Update(); while(1) { if(Control_Flag) { Control_Loop(); Control_Flag = 0; } // Sent_Data_to_Vofa(); } } SPWM.c:#include "stm32f10x.h" // Device header #include "Serial.h" #include "PID.h" #include <math.h> #include "ADC_DMA.h" #include "SPWM.h" //DMA传输正弦表进TIM1_CCR1中的据量 #define BufferSize_Sample 1600 // uint8_t TIM_DeadTime = 50; //待确定 //用于串口的定时中断采CCR1送入上位机,此为预备组 //#define Sample_CCR_Num 100 //uint16_t Sample_Ready_CCR1[100];//TIM1_CCR1的采样,缓冲采样组1,采样完毕后转移进Serial.c中的Buffer_to_Sent[]中 //uint16_t Sample_Ready_CCR2[100];//TIM1_CCR1的采样,缓冲采样组2,采样完毕后转移进Serial.c中的Buffer_to_Sent[]中 //volatile uint16_t *Current_CCR_Buffer = Sample_Ready_CCR1; //volatile uint8_t Buffer_Ready_Flag = 0; //采满200个样点的标志位 volatile uint16_t *Current_SPWM_ReadyBuffer; //指向当前就绪SPWM缓冲区,用于更新SPWM新表 volatile uint8_t SPWM_BufferReady_Flag = 0; //SPWM缓冲区就绪标志位 volatile uint16_t* const DMA_RemainIndex = (volatile uint16_t*)(&DMA1_Channel1->CNDTR); //DMA1_Channel1(搬运ADC)当前剩余据 volatile Rms_Windows rms_windows = {0,0,0}; uint16_t DMA_CurrentIndex; //DMA1_Channel1当前索引 uint8_t Can_Get_RmsFlag = 0; //可获取有效值标志位 uint16_t SPWM_Data[BufferSize_Sample] = //SPWM的CCR值,大缓冲组,每800个点为一个正弦周期(20ms),每个TIM1周期更新两个点 { 900,906,912,918,925,931,937,943,950,956,962,969,975,981,987,994, 1000,1006,1012,1018,1025,1031,1037,1043,1049,1056,1062,1068,1074,1080,1086,1092, 1098,1105,1111,1117,1123,1129,1135,1141,1147,1153,1159,1165,1170,1176,1182,1188, 1194,1200,1206,1211,1217,1223,1229,1234,1240,1246,1251,1257,1263,1268,1274,1279, 1285,1290,1296,1301,1307,1312,1317,1323,1328,1333,1339,1344,1349,1354,1360,1365, 1370,1375,1380,1385,1390,1395,1400,1405,1409,1414,1419,1424,1429,1433,1438,1443, 1447,1452,1456,1461,1465,1470,1474,1478,1483,1487,1491,1495,1500,1504,1508,1512, 1516,1520,1524,1528,1532,1535,1539,1543,1547,1550,1554,1558,1561,1565,1568,1572, 1575,1578,1582,1585,1588,1591,1594,1597,1601,1604,1607,1609,1612,1615,1618,1621, 1623,1626,1629,1631,1634,1636,1639,1641,1643,1646,1648,1650,1652,1654,1656,1658, 1660,1662,1664,1666,1668,1669,1671,1673,1674,1676,1677,1679,1680,1682,1683,1684, 1685,1686,1688,1689,1690,1691,1692,1692,1693,1694,1695,1695,1696,1697,1697,1698, 1698,1698,1699,1699,1699,1699,1699,1699,1700,1699,1699,1699,1699,1699,1699,1698, 1698,1698,1697,1697,1696,1695,1695,1694,1693,1692,1692,1691,1690,1689,1688,1686, 1685,1684,1683,1682,1680,1679,1677,1676,1674,1673,1671,1669,1668,1666,1664,1662, 1660,1658,1656,1654,1652,1650,1648,1646,1643,1641,1639,1636,1634,1631,1629,1626, 1623,1621,1618,1615,1612,1609,1607,1604,1601,1597,1594,1591,1588,1585,1582,1578, 1575,1572,1568,1565,1561,1558,1554,1550,1547,1543,1539,1535,1532,1528,1524,1520, 1516,1512,1508,1504,1500,1495,1491,1487,1483,1478,1474,1470,1465,1461,1456,1452, 1447,1443,1438,1433,1429,1424,1419,1414,1409,1405,1400,1395,1390,1385,1380,1375, 1370,1365,1360,1354,1349,1344,1339,1333,1328,1323,1317,1312,1307,1301,1296,1290, 1285,1279,1274,1268,1263,1257,1251,1246,1240,1234,1229,1223,1217,1211,1206,1200, 1194,1188,1182,1176,1170,1165,1159,1153,1147,1141,1135,1129,1123,1117,1111,1105, 1098,1092,1086,1080,1074,1068,1062,1056,1049,1043,1037,1031,1025,1018,1012,1006, 1000,994,987,981,975,969,962,956,950,943,937,931,925,918,912,906, 900,893,887,881,874,868,862,856,849,843,837,830,824,818,812,805, 799,793,787,781,774,768,762,756,750,743,737,731,725,719,713,707, 701,694,688,682,676,670,664,658,652,646,640,634,629,623,617,611, 605,599,593,588,582,576,570,565,559,553,548,542,536,531,525,520, 514,509,503,498,492,487,482,476,471,466,460,455,450,445,439,434, 429,424,419,414,409,404,399,394,390,385,380,375,370,366,361,356, 352,347,343,338,334,329,325,321,316,312,308,304,299,295,291,287, 283,279,275,271,267,264,260,256,252,249,245,241,238,234,231,227, 224,221,217,214,211,208,205,202,198,195,192,190,187,184,181,178, 176,173,170,168,165,163,160,158,156,153,151,149,147,145,143,141, 139,137,135,133,131,130,128,126,125,123,122,120,119,117,116,115, 114,113,111,110,109,108,107,107,106,105,104,104,103,102,102,101, 101,101,100,100,100,100,100,100,100,100,100,100,100,100,100,101, 101,101,102,102,103,104,104,105,106,107,107,108,109,110,111,113, 114,115,116,117,119,120,122,123,125,126,128,130,131,133,135,137, 139,141,143,145,147,149,151,153,156,158,160,163,165,168,170,173, 176,178,181,184,187,190,192,195,198,202,205,208,211,214,217,221, 224,227,231,234,238,241,245,249,252,256,260,264,267,271,275,279, 283,287,291,295,299,304,308,312,316,321,325,329,334,338,343,347, 352,356,361,366,370,375,380,385,390,394,399,404,409,414,419,424, 429,434,439,445,450,455,460,466,471,476,482,487,492,498,503,509, 514,520,525,531,536,542,548,553,559,565,570,576,582,588,593,599, 605,611,617,623,629,634,640,646,652,658,664,670,676,682,688,694, 701,707,713,719,725,731,737,743,750,756,762,768,774,781,787,793, 799,805,812,818,824,830,837,843,849,856,862,868,874,881,887,893, 900,906,912,918,925,931,937,943,950,956,962,969,975,981,987,994, 1000,1006,1012,1018,1025,1031,1037,1043,1049,1056,1062,1068,1074,1080,1086,1092, 1098,1105,1111,1117,1123,1129,1135,1141,1147,1153,1159,1165,1170,1176,1182,1188, 1194,1200,1206,1211,1217,1223,1229,1234,1240,1246,1251,1257,1263,1268,1274,1279, 1285,1290,1296,1301,1307,1312,1317,1323,1328,1333,1339,1344,1349,1354,1360,1365, 1370,1375,1380,1385,1390,1395,1400,1405,1409,1414,1419,1424,1429,1433,1438,1443, 1447,1452,1456,1461,1465,1470,1474,1478,1483,1487,1491,1495,1500,1504,1508,1512, 1516,1520,1524,1528,1532,1535,1539,1543,1547,1550,1554,1558,1561,1565,1568,1572, 1575,1578,1582,1585,1588,1591,1594,1597,1601,1604,1607,1609,1612,1615,1618,1621, 1623,1626,1629,1631,1634,1636,1639,1641,1643,1646,1648,1650,1652,1654,1656,1658, 1660,1662,1664,1666,1668,1669,1671,1673,1674,1676,1677,1679,1680,1682,1683,1684, 1685,1686,1688,1689,1690,1691,1692,1692,1693,1694,1695,1695,1696,1697,1697,1698, 1698,1698,1699,1699,1699,1699,1699,1699,1700,1699,1699,1699,1699,1699,1699,1698, 1698,1698,1697,1697,1696,1695,1695,1694,1693,1692,1692,1691,1690,1689,1688,1686, 1685,1684,1683,1682,1680,1679,1677,1676,1674,1673,1671,1669,1668,1666,1664,1662, 1660,1658,1656,1654,1652,1650,1648,1646,1643,1641,1639,1636,1634,1631,1629,1626, 1623,1621,1618,1615,1612,1609,1607,1604,1601,1597,1594,1591,1588,1585,1582,1578, 1575,1572,1568,1565,1561,1558,1554,1550,1547,1543,1539,1535,1532,1528,1524,1520, 1516,1512,1508,1504,1500,1495,1491,1487,1483,1478,1474,1470,1465,1461,1456,1452, 1447,1443,1438,1433,1429,1424,1419,1414,1409,1405,1400,1395,1390,1385,1380,1375, 1370,1365,1360,1354,1349,1344,1339,1333,1328,1323,1317,1312,1307,1301,1296,1290, 1285,1279,1274,1268,1263,1257,1251,1246,1240,1234,1229,1223,1217,1211,1206,1200, 1194,1188,1182,1176,1170,1165,1159,1153,1147,1141,1135,1129,1123,1117,1111,1105, 1098,1092,1086,1080,1074,1068,1062,1056,1049,1043,1037,1031,1025,1018,1012,1006, 1000,994,987,981,975,969,962,956,950,943,937,931,925,918,912,906, 900,893,887,881,874,868,862,856,849,843,837,830,824,818,812,805, 799,793,787,781,774,768,762,756,750,743,737,731,725,719,713,707, 701,694,688,682,676,670,664,658,652,646,640,634,629,623,617,611, 605,599,593,588,582,576,570,565,559,553,548,542,536,531,525,520, 514,509,503,498,492,487,482,476,471,466,460,455,450,445,439,434, 429,424,419,414,409,404,399,394,390,385,380,375,370,366,361,356, 352,347,343,338,334,329,325,321,316,312,308,304,299,295,291,287, 283,279,275,271,267,264,260,256,252,249,245,241,238,234,231,227, 224,221,217,214,211,208,205,202,198,195,192,190,187,184,181,178, 176,173,170,168,165,163,160,158,156,153,151,149,147,145,143,141, 139,137,135,133,131,130,128,126,125,123,122,120,119,117,116,115, 114,113,111,110,109,108,107,107,106,105,104,104,103,102,102,101, 101,101,100,100,100,100,100,100,100,100,100,100,100,100,100,101, 101,101,102,102,103,104,104,105,106,107,107,108,109,110,111,113, 114,115,116,117,119,120,122,123,125,126,128,130,131,133,135,137, 139,141,143,145,147,149,151,153,156,158,160,163,165,168,170,173, 176,178,181,184,187,190,192,195,198,202,205,208,211,214,217,221, 224,227,231,234,238,241,245,249,252,256,260,264,267,271,275,279, 283,287,291,295,299,304,308,312,316,321,325,329,334,338,343,347, 352,356,361,366,370,375,380,385,390,394,399,404,409,414,419,424, 429,434,439,445,450,455,460,466,471,476,482,487,492,498,503,509, 514,520,525,531,536,542,548,553,559,565,570,576,582,588,593,599, 605,611,617,623,629,634,640,646,652,658,664,670,676,682,688,694, 701,707,713,719,725,731,737,743,750,756,762,768,774,781,787,793, 799,805,812,818,824,830,837,843,849,856,862,868,874,881,887,893 }; void SPWM_BDTR_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //CH1为PA8 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //CH1N互补为PB13 GPIO_Init(GPIOB,&GPIO_InitStructure); DMA_DeInit(DMA1_Channel2); //TIM1_CC1映射在DMA1的通道2 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&TIM1 ->CCR1; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SPWM_Data; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = BufferSize_Sample; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel2,&DMA_InitStructure); DMA_Cmd(DMA1_Channel2,ENABLE); TIM1->CCR1 = SPWM_Data[0]; //先校正第一个CCR为组SPWM_Data[0],使得第一次CC1事件触发时DMA搬运SPWM_Data[1]进CCR1 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //中央对齐模式2,0-->ARR-->0的计模式,向下计阶段ARR-->0时CNT = 0时产生更新事件 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned2; TIM_TimeBaseStructure.TIM_Period = 1800-1; //20k的频率,ARR = 3600-1 TIM_TimeBaseStructure.TIM_Prescaler = 1-1; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure); TIM_ClearFlag(TIM1,TIM_FLAG_CC1); //初始化前清除CC1标志位 TIM_ClearFlag(TIM2,TIM_FLAG_CC2); //初始化前清除CC2标志位 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //主路 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //互补路 TIM_OCInitStructure.TIM_Pulse = 0; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC1Init(TIM1,&TIM_OCInitStructure); TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //主路 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; //互补路 TIM_OCInitStructure.TIM_Pulse = 300; TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OC2Init(TIM1,&TIM_OCInitStructure); TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStructure.TIM_DeadTime = TIM_DeadTime; TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; //先不使用刹车 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; //刹车触发极性,低电平 TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Disable; //故障后不自动恢复输出,需自行手动恢复 TIM_BDTRConfig(TIM1,&TIM_BDTRInitStructure); // NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn; //0 0 // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); // TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA1_Channel2, DMA_IT_TC | DMA_IT_HT, ENABLE); NVIC_EnableIRQ(DMA1_Channel2_IRQn); // 启用DMA中断通道2 TIM_DMACmd(TIM1,TIM_DMA_CC1,ENABLE); //TIM1的CC1事件更新时触发DMA TIM_ARRPreloadConfig(TIM1,ENABLE); //预装载ARR TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //预装载 TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_OC2Ref); //TIM1_CC2触发ADC TIM_CtrlPWMOutputs(TIM1,ENABLE); //使能输出主PWM TIM_Cmd(TIM1,ENABLE); } void PWM_SetCCR(TIM_TypeDef* TIMx,uint8_t CHx,uint16_t Compare,uint16_t Upper_LimitCCR) //占空比设置 { if(CHx<1||CHx>4) return; if(Compare > Upper_LimitCCR) Compare = Upper_LimitCCR; switch (CHx) { case 1:TIM_SetCompare1(TIMx,Compare);break; case 2:TIM_SetCompare2(TIMx,Compare);break; case 3:TIM_SetCompare3(TIMx,Compare);break; case 4:TIM_SetCompare4(TIMx,Compare);break; } } uint16_t PWM_GetCCR(TIM_TypeDef* TIMx,uint8_t CHx) //参1:定时器TIMX 参2:通道,可为1~4 { if(CHx<1||CHx>4) return 0; uint16_t CCR; switch (CHx) { case 1:CCR =TIM_GetCapture1(TIMx);break; case 2:CCR =TIM_GetCapture2(TIMx);break; case 3:CCR =TIM_GetCapture3(TIMx);break; case 4:CCR =TIM_GetCapture4(TIMx);break; } return CCR; } void SPWM_Update(float Gain,volatile uint16_t *Ready_Buffer) //正弦表更新,传入Current_SPWM_ReadyBuffer指向待写入的缓冲区 { static float last_Gain = 1.0f; int Offset_Val,New_Val; if(SPWM_BufferReady_Flag&&fabs(Gain - last_Gain)>0.005f) { SPWM_BufferReady_Flag = 0; for(uint16_t i=0;i<800;i++ ) { Offset_Val = (int16_t)(Ready_Buffer[i] -900); New_Val = (int16_t)((Offset_Val * Gain) + 900); if(New_Val < 60) New_Val = 60; else if(New_Val > 1740) New_Val = 1740; Ready_Buffer[i] = (uint16_t)New_Val; } last_Gain = Gain; } } void Rms_WindowsInit(void) { rms_windows.Volt_SquareSum = 0; rms_windows.Cur_SquareSum = 0; rms_windows.Count = 0; } void Rms_WindowsUpdate(void) { uint16_t DMA_Remain = *DMA_RemainIndex; //DMA传输剩余据量 DMA_CurrentIndex = ADC_DMA_BufferSize - DMA_Remain; //DMA当前索引 //需移除点的索引,一个正弦周期(20ms)共采800个点,每8个点取一个点,实际一共仅取100个采样点 uint16_t Old_Index = (DMA_CurrentIndex - DMA_CurrentIndex%8 + ADC_DMA_BufferSize - ADC_BufferSize)%ADC_DMA_BufferSize; uint16_t New_Index = DMA_CurrentIndex - DMA_CurrentIndex%8; uint32_t Old_Value = ADC_Dual_Value[Old_Index]; //需移除的点的32位值 uint32_t New_Value = ADC_Dual_Value[New_Index]; //解析需移除的点的值为高16位的电流值和低16位的电压值 uint16_t New_Volt = New_Value & 0xFFFF; uint16_t New_Cur = New_Value >> 16; uint16_t Old_Volt = Old_Value & 0xFFFF; uint16_t Old_Cur = Old_Value >> 16; //更新新的平方和 rms_windows.Volt_SquareSum += (New_Volt * New_Volt - Old_Volt * Old_Volt); rms_windows.Cur_SquareSum += (New_Cur * New_Cur - Old_Cur * Old_Cur); } float Get_Volt_RmsValue(void) { if(Can_Get_RmsFlag) { return sqrtf((float)rms_windows.Volt_SquareSum / ADC_BufferSize *3.3f/4095.0f); } else return 0; } float Get_Cur_RmsValue(void) { if(Can_Get_RmsFlag) { return sqrtf((float)rms_windows.Cur_SquareSum / ADC_BufferSize *3.3f/4095.0f); } else return 0; } void DMA1_Channel2_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_HT2)) //上半缓冲传输完成,上次的表已经传输完了,该传输上次表传输完成之前PID已生成好的新表了 { SPWM_BufferReady_Flag = 1; //置上半缓冲就绪1,该传输下半缓冲区了 Current_SPWM_ReadyBuffer = SPWM_Data; //当前源地址的指针指向下半缓冲区,将上次PID已更新好的据写入TIM1_CC1 DMA_ClearITPendingBit(DMA1_IT_HT2); } if(DMA_GetITStatus(DMA1_IT_TC2)) //下半缓冲完成,上次的表已经传输完了,该传输上次表传输完成之前PID已生成好的新表了 { SPWM_BufferReady_Flag = 2; //置下半缓冲就绪2,该传输上半缓冲区了 Current_SPWM_ReadyBuffer = SPWM_Data+ 800; //当前源地址的指针指向上半缓冲区,将上次PID已更新好的据写入TIM1_CC1 DMA_ClearITPendingBit(DMA1_IT_TC2); } } //void TIM1_UP_IRQHandler(void) //{ //// static uint8_t TIM_Count_Sample_CCR = 0; //// static uint8_t Sample_Num = 0; // if(TIM_GetITStatus(TIM1,TIM_IT_Update)) // { // // ADC_SoftwareStartConvCmd(ADC1,ENABLE); //每个TIM1中断软件触发ADC采样 // Window_UpdateFlag = 1; // // TIM_ClearITPendingBit(TIM1, TIM_IT_Update); // // // //if(++cycle_count >= 16000) //16000个TIM1中断时复位DMA // // { // // DMA_Cmd(DMA1_Channel2, DISABLE); //先关闭才能配置DMA // // DMA1_Channel2->CNDTR = BufferSize_Sample; // // DMA1_Channel2->CMAR = (uint32_t)SPWM_Data; // // TIM1->CCR1 = SPWM_Data[0]; //校正第一个CCR为组SPWM_Data[0],使得第一次CC1事件触发时DMA搬运SPWM_Data[1]进CCR1 // // DMA_Cmd(DMA1_Channel2, ENABLE); // // cycle_count = 0; // // } // // // //// if(++TIM_Count_Sample_CCR >= 40) //每40次定时中断(0.2ms)就采一次CCR1进Sample_CCR【】中 //// { //// TIM_Count_Sample_CCR = 0; ////__disable_irq(); //原子保护,禁止中断 //// if(Sample_Num < Sample_CCR_Num) //如果组没填满到Sample_CCR_Num这个次,那就将CCR1存进去 //// { //// Current_CCR_Buffer[Sample_Num] = TIM1->CCR1; //// Sample_Num++; //// } ////__enable_irq(); //原子保护恢复,允许中断 //// if(Sample_Num >= Sample_CCR_Num) //如果组已经采满Sample_CCR_Num这个次,就产生标志位 //// { ////__disable_irq(); //原子保护,禁止中断 //// if(Current_CCR_Buffer == Sample_Ready_CCR1) //寻找当前指向哪个缓冲区 //// { //// Current_CCR_Buffer = Sample_Ready_CCR2; //缓冲区1满,切换缓冲区2 //// Buffer_Ready_Flag = 1; //标志位置1 //// } //// else //// { //// Current_CCR_Buffer = Sample_Ready_CCR1; //缓冲区2满,切换缓冲区1 //// Buffer_Ready_Flag = 2; //标志位置2 //// } //// Sample_Num = 0; //将Sample_Num复位 ////__enable_irq(); //原子保护恢复,允许中断 //// //// } //// } // // } // //} // // // // ADC_DMA.c:#include "stm32f10x.h" #include "PID.h" #include "Delay.h" #include "ADC_DMA.h" #include "SPWM.h" #include "OLED.h" #include "OLED_Data.h" #include<math.h> #define ChannelNum 1 uint32_t ADC_Dual_Value[ADC_DMA_BufferSize]; //使用双ADC规则同步 32位的ADC1_DR存据,低16位为ADC1 高16位为ADC2 uint16_t Volt_Value[SimplifyADC_BufferSize]; uint16_t Cur_Value[SimplifyADC_BufferSize]; float Void_Gain = 11; float Cur_Gain = 1.47205; volatile uint8_t ADC_DMA_CompleteFlag = 0; // DMA缓冲区就绪标志 volatile uint32_t *Current_ADC_Buffer; //指向当前就绪缓冲区 void TIM2_PWM_Init(void) //TIM2的通道1产生的PWM用于开关,通道2产生的PWM用于触发ADC采样 { // 时基参配置(产生100kHz PWM) TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0输出PWM用于开关 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 定时器配置 TIM_TimeBaseStructure.TIM_Period = 1000-1; // ARR = 1000 TIM_TimeBaseStructure.TIM_Prescaler = 8-1; // PSC = 71 TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // PWM通道2配置(PA1)用于触发ADC TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // 时序:---------_____(采样)_____ TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = 300; // 75%占空比时采样(此处处于mos关断中间时刻) TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM2, &TIM_OCInitStructure); // 配置定时器触发输出 // TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_OC2Ref); // TIM_CtrlPWMOutputs(TIM2, ENABLE); // TIM_Cmd(TIM2, ENABLE); // 启动定时器 } void TIM4_Init(void) //用于中断刷新OLED { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); // 时基参配置 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; // 定时器配置 TIM_TimeBaseStructure.TIM_Period = 10000-1; // ARR TIM_TimeBaseStructure.TIM_Prescaler = 720-1; // PSC TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); TIM_InternalClockConfig(TIM4); NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); TIM_Cmd(TIM4, ENABLE); // 启动定时器 } void ADC_DMA_Init(void) //双ADC规则同步采样,PB0采电压,PB1采电流 { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; DMA_InitTypeDef DMA1_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1| RCC_APB2Periph_ADC2, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 配置PB0(ADC1通道8)采电压、PB1(ADC1通道9)采电流为模拟输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOB, &GPIO_InitStructure); // DMA配置 DMA_DeInit(DMA1_Channel1); DMA1_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA1_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_Dual_Value; //ADC_DMA_BufferSize个据的大缓冲组 DMA1_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA1_InitStructure.DMA_BufferSize = ADC_DMA_BufferSize; DMA1_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA1_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA1_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA1_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA1_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA1_InitStructure.DMA_Priority = DMA_Priority_High; DMA1_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA1_InitStructure); DMA_Cmd(DMA1_Channel1, ENABLE); //配置ADC1,主ADC ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 启用扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //单次转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC2; //使用T1_CC2触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE); NVIC_EnableIRQ(DMA1_Channel1_IRQn); // 启用DMA中断通道1 ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_55Cycles5); // 配置通道顺序(通道8) PB0对应序列1采电压 ADC_DMACmd(ADC1, ENABLE); //配置ADC2,从ADC,配置与ADC1相同 ADC_Init(ADC2, &ADC_InitStructure); ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 1, ADC_SampleTime_55Cycles5); //// 配置通道顺序(通道9) PB1对应序列1采电流 //操作ADC1_CR1寄存器之前先关闭ADC1和ADC2 ADC_Cmd(ADC1, DISABLE); ADC_Cmd(ADC2, DISABLE); //操作ADC1_CR1的位19:16位[3:0] = 0110 为规则同步模式 uint32_t tmp = ADC1->CR1; tmp &= 0xFFF0FFFF; tmp |= 0x00060000; ADC1->CR1 = tmp; // 先ADC2校准 ADC_Cmd(ADC2, ENABLE); Delay_us(1); ADC_ResetCalibration(ADC2); while(ADC_GetResetCalibrationStatus(ADC2)); ADC_StartCalibration(ADC2); while(ADC_GetCalibrationStatus(ADC2)); // ADC1校准 ADC_Cmd(ADC1, ENABLE); Delay_us(1); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); // 启用外部触发 ADC_ExternalTrigConvCmd(ADC1, ENABLE); ADC_ExternalTrigConvCmd(ADC2, ENABLE); } void ADC_DMAInit(void) { // TIM2_PWM_Init(); //全桥不需TIM2_CC2触发ADC采样,需要TIM1_CC1触发ADC ADC_DMA_Init(); } void Get_ADC_Value(volatile uint32_t *ADC_Value) //解析32位采样据,暂不用 { for(int i=0;i<ADC_BufferSize;i++) { Volt_Value[i] = ADC_Value[i] & 0xFFFF; Cur_Value[i] = ADC_Value[i] >>16; } } void DMA1_Channel1_IRQHandler(void) { if(DMA_GetITStatus(DMA1_IT_HT1)) //DMA半传输完成标志位 { Can_Get_RmsFlag = 1; //标记前半缓冲区就绪,前400个据已就绪,可以调用float Get_Volt_RmsValue()和float Get_Cur_RmsValue(); //ADC_DMA_CompleteFlag = 1; // 标记前半缓冲区就绪,前400个据已就绪 // Current_ADC_Buffer = &ADC_Dual_Value[0]; //指针指向缓冲区【0】 DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, DISABLE); //第一次采满一个周期就关闭中断,此后方可调用float Get_Volt_RmsValue()和float Get_Cur_RmsValue(); DMA_ClearITPendingBit(DMA1_IT_HT1); } //if(DMA_GetITStatus(DMA1_IT_TC1)) //DMA全部传输完成标志位 //{ // ADC_DMA_CompleteFlag = 2; // 标记后半缓冲区就绪,后400个据已就绪 // Current_ADC_Buffer = &ADC_Dual_Value[200]; //指针指向缓冲区【400】 // DMA_ClearITPendingBit(DMA1_IT_TC1); // } } void TIM4_UP_IRQHandler(void) { if(TIM_GetITStatus(TIM4,TIM_IT_Update)) { Sam_Vol = (uint16_t)(filtered_ADC_volt(Volt_Value)*1000); //采样电压,到时去实验测阻值比来乘上系得到输出电压 // Sam_Cur = (uint16_t)(filtered_ADC_volt(Cur_Value)*1000/Cur_Gain); //采样电流的 // vol_DAC = (uint16_t)(filtered_ADC_volt(Volt_Value)*1000*Void_Gain);//输出电压 // // OLED_ShowNum(56, 0,vol_DAC/10000,1,OLED_8X16); //十位 // OLED_ShowNum(64, 0,vol_DAC%10000/1000,1,OLED_8X16); //个位 // OLED_ShowChar(72, 0,'.',OLED_8X16); // OLED_ShowNum(80, 0,vol_DAC%1000/100,1,OLED_8X16); //十分位 // OLED_ShowNum(88, 0,vol_DAC%100/10,1,OLED_8X16); //百分位 // OLED_ShowNum(96, 0,vol_DAC%10,1,OLED_8X16); //千分位 // OLED_ShowChar(112,0,'V',OLED_8X16); OLED_ShowNum(72,16,Sam_Vol/10000,1,OLED_8X16); //十位 OLED_ShowNum(80,16,Sam_Vol%10000/1000,1,OLED_8X16); //个位 OLED_ShowChar(88,16,'.',OLED_8X16); OLED_ShowNum(96,16,Sam_Vol%1000/100,1,OLED_8X16); //十分位 OLED_ShowNum(104,16,Sam_Vol%100/10,1,OLED_8X16); //百分位 OLED_ShowNum(112,16,Sam_Vol%10,1,OLED_8X16); //千分位 OLED_ShowChar(120,16,'V',OLED_8X16); // OLED_ShowNum(72, 32,Sam_Cur/10000,1,OLED_8X16); //十位 // OLED_ShowNum(80, 32,Sam_Cur%10000/1000,1,OLED_8X16); //个位 // OLED_ShowChar(88, 32,'.',OLED_8X16); // OLED_ShowNum(96, 32,Sam_Cur%1000/100,1,OLED_8X16); //十分位 // OLED_ShowNum(104, 32,Sam_Cur%100/10,1,OLED_8X16); //百分位 // OLED_ShowNum(112, 32,Sam_Cur%10,1,OLED_8X16); //千分位 // OLED_ShowChar(120,32,'A',OLED_8X16); // OLED_ShowNum(0,48,PWM_GetCCR(TIM1,1),4,OLED_8X16); //OLED_Update(); // OLED_UpdateArea(0,16,128,16); TIM_ClearITPendingBit(TIM4,TIM_IT_Update); } } PID.c:#include "stm32f10x.h" // Device header #include "PID.h" #include "SPWM.h" #include <math.h> #include "ADC_DMA.h" #include <string.h> #define Volt_Target 2.0f //目标电压 #define Cur_Max 5.0f #define Steady_State_rate 0.0007f // 1%变化视为稳态 #define Enter_Steady_Count 10 // 连续20次在阈值内视为稳态 #define Max_Steady_Step 8 // 稳态时CCR最大步长(0.001占空比步长) #define SAMPLE_SIZE 64 // 采样组大小 float Gain = 1.0f; //SPWM幅值缩放因子 uint8_t Control_Flag =0; PIDController pid = {.in_steady_state = 0, .steady_count = 0}; void Timer3_Init(void) //使用TIM3做定时中断 { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); TIM_InternalClockConfig(TIM3); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStructure.TIM_Period = 4000-1; //2ms的定时中断 TIM_TimeBaseInitStructure.TIM_Prescaler = 72-1; TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure); TIM_ClearFlag(TIM3,TIM_IT_Update); TIM_ITConfig(TIM3,TIM_EventSource_Update,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3,ENABLE); } void PID_Init(float Volt_Kp,float Volt_Ki, float Volt_Kd,float Cur_Kp,float Cur_Ki, float Cur_Kd) { // 初始PID参(需调试优化) pid.Volt_Kp = Volt_Kp; // 电压比例系 pid.Volt_Ki = Volt_Ki; // 电压积分系 pid.Volt_Kd = Volt_Kd; // 电压微分系 pid.Cur_Kp = Cur_Kp; // 电压比例系 pid.Cur_Ki = Cur_Ki; // 电压积分系 pid.Cur_Kd = Cur_Kd; // 电压微分系 pid.Volt_integral_sum = 0; //电压积分累加项 pid.Cur_integral_sum = 0; //电流积分累加项 pid.Max_Current = 0; //最大电流有效值 pid.Cur_Vref = 0; pid.Volt_prev_error = 0; //电压上次误差 pid.Cur_prev_error = 0; //电流上次误差 // 输出限幅 pid.output_min = 0.1f; pid.output_max = 1.05f; Timer3_Init(); } float PID_Compute(float Volt_Rms ,float Cur_Rms) { // 计算当前误差 (电压误差) float Volt_error = Volt_Target - Volt_Rms; float error_threshold = Volt_Target * Steady_State_rate; //进入稳态误差的小小误差 if(fabs(Volt_error) <= error_threshold) //判断误差值连续20次<0.01V的电压时进入稳态 { pid.steady_count++; } else { pid.steady_count = 0; pid.in_steady_state = 0; } if(pid.steady_count >= Enter_Steady_Count) { pid.in_steady_state = 1; } // 计算P项 float Volt_P = pid.Volt_Kp * Volt_error; // 计算I项 if(pid.in_steady_state) // 稳态时仅当|error|较大时才积分 { if(fabs(Volt_error) > Steady_State_rate* Volt_Target/1) { pid.Volt_integral_sum += Volt_error; } } else // 动态变化中正常积分 { pid.Volt_integral_sum += Volt_error; } float Volt_I = pid.Volt_Ki * pid.Volt_integral_sum; // 计算D项 (基于误差变化率) float error_derivative = (Volt_error - pid.Volt_prev_error); float Volt_D = pid.Volt_Kd * error_derivative; // 计算电压外环输出 pid.Cur_Vref = Volt_P + Volt_I + Volt_D; // 输出限幅处理 if(pid.Cur_Vref > pid.Max_Current) { pid.Cur_Vref = pid.Max_Current; } else if(pid.Cur_Vref < 0) { pid.Cur_Vref = 0; } pid.Volt_prev_error = Volt_error; float Cur_error = pid.Cur_Vref - Cur_Rms; //内环P float Cur_P = pid.Cur_Kp * Cur_error; //内环I pid.Cur_integral_sum += Cur_error; float Cur_I = pid.Cur_Ki * pid.Cur_integral_sum; //内环D float Cur_D = pid.Cur_Kd * (Cur_error - pid.Cur_prev_error); float output = Cur_P + Cur_I + Cur_D; pid.Cur_prev_error = Cur_error; //输出限幅 if(output > pid.output_max) { output = pid.output_max; if(Cur_error > 0)pid.Cur_integral_sum -= Cur_error; //超则回退积分 } if(output < pid.output_min) { output = pid.output_min; if(Cur_error < 0)pid.Cur_integral_sum -= Cur_error; } return output; } float filtered_ADC_volt(uint16_t *adc_values) //中值滤波函,滤波采样组中的据 { uint16_t temp[SAMPLE_SIZE]; // 1. for(uint8_t i=0; i<SAMPLE_SIZE; i++) { temp[i] = adc_values[i]; } // 2. 排序 for(uint8_t i=0; i<SAMPLE_SIZE-1; i++) { for(uint8_t j=0; j<SAMPLE_SIZE-1-i; j++) { if(temp[j] > temp[j+1]) { uint16_t swap = temp[j]; temp[j] = temp[j+1]; temp[j+1] = swap; } } } // 3. 去掉最大最小值并计算均值 uint32_t sum = 0; for(uint8_t i=5; i<SAMPLE_SIZE-5; i++) // 掐头去尾(去掉最大最小值) { sum += temp[i]; } float result = sum / (float)(SAMPLE_SIZE - 10); return result*3.3f/4095.0; //返回组中去除最大最小值后的平均值(注:该值为模拟量) } float Rms_ADC_Volt(uint16_t *adc_values) { uint32_t Sum = 0; float volt; for(uint16_t i=0;i<SAMPLE_SIZE;i+=4) { Sum += (uint32_t)(adc_values[i] * adc_values[i]); Sum += (uint32_t)(adc_values[i+1] * adc_values[i+1]); Sum += (uint32_t)(adc_values[i+2] * adc_values[i+2]); Sum += (uint32_t)(adc_values[i+3] * adc_values[i+3]); } volt = 3.3f*sqrt((float)Sum/SAMPLE_SIZE)/4095.0f; return volt; } void Control_Loop(void) { Rms_WindowsUpdate(); //更新平方和 float Volt_Rms = Get_Volt_RmsValue(); float Cur_Rms =Get_Cur_RmsValue(); Gain = PID_Compute(Volt_Rms,Cur_Rms); //求采样有效值(0~3.3V)送入PID,返回缩放增益Gain SPWM_Update(Gain,Current_SPWM_ReadyBuffer); } void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) { Control_Flag = 1; TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } } 请检查代码并分析,谢谢
最新发布
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值