搜索
bottom↓
回复: 104

给大家一个只用STM32的一个定时器输出4路频率、脉宽任意可调的例子

  [复制链接]

出0入90汤圆

发表于 2010-9-19 20:52:30 | 显示全部楼层 |阅读模式
这几天弄一个STM32的PWM的程序,要求4路PWM输出,1路PWM输入;我弄了3天,找了N多资料;因为4路PWM输出频率独立,脉宽可调,如果使用定时器的PWM功能的话,虽然每个定时器有4路输出,但是那频率就是固定的了。我用的STM32C8T6,有TIM1,2,3,4,一开始我每个定时器输出一路PWM,然后用定时器2同时输入一路PWM,结果问题来了。输入的PWM的频率不能低于输出的PWM的频率。到处找资料也找不到!终于,让我看官方的文档找到资料了,可以使用定时器的比较输出模式,然后在中断中调节各个通道的比较值。于是,这个东西就做成了。研究了3天。对于STM32的定时器和串口有了一定的了解了。
考虑到网上挺少的多路PWM多种频率输出的范例。而不是每个人会去关注官方的文档。所以,我就把我的这个程序公布出来,让不知道的人,可以快速了解下!官方的范例给了我很多的帮助,感谢它。

程序中TIM2 4个通道上电默认输出频率为20HZ,脉宽为20ms的PWM波形。TIM3的CH2通道作为PWM输入。同时USART1作为波特率9600,其他默认的串口通信。STM32每秒钟按照:PWM输入频率,PWM输入脉宽,CH1频率,CH1脉宽,CH2频率,CH2脉宽,CH3频率,CH3脉宽,CH4频率,CH4脉宽按照十六进制的形式把数据串口输出;同时可以通过串口对下方的频率进行修改,协议暂定为 0x55 通道N(01,02,03,04任选,其他的被忽略),通道N(频率,16 - 255hz以内,16进制),通道N(脉宽,ms为单位,自行计算,16进制),0xaa;    程序看懂后,可以自行修改相关的参数,自己加个上位机,就好玩了!
点击此处下载 ourdev_584277D6J2EZ.rar(文件大小:314K) (原文件名:PWM.rar)

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2010-9-19 20:54:24 | 显示全部楼层
顶!

出0入0汤圆

发表于 2010-9-19 21:04:36 | 显示全部楼层
我也顶一个

出0入0汤圆

发表于 2010-9-19 21:04:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-19 21:25:09 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-20 01:31:05 | 显示全部楼层
兄弟,你搞电机控制?

出0入90汤圆

 楼主| 发表于 2010-9-20 07:48:17 | 显示全部楼层
我不搞电机控制,我搞电机保护。上面的程序是随便写写的!

出0入0汤圆

发表于 2010-9-20 07:50:13 | 显示全部楼层
LZ厉害

出0入0汤圆

发表于 2010-9-20 08:09:23 | 显示全部楼层
记号

出0入0汤圆

发表于 2010-9-20 08:27:22 | 显示全部楼层
谢谢共享!

出0入0汤圆

发表于 2010-9-20 08:44:05 | 显示全部楼层
晕,前两天正为三路独立的PWM频率和占空比而发愁呢,因为MEGA的3路PWM没有那么灵活,现在用这个方法应该可以解决了,但是STM没有开发工具啊,哎!又得花银子来折腾了!

出0入0汤圆

发表于 2010-9-20 08:47:54 | 显示全部楼层
留爪

出0入0汤圆

发表于 2010-9-20 08:52:34 | 显示全部楼层
mark

出0入90汤圆

 楼主| 发表于 2010-9-20 09:00:11 | 显示全部楼层
山寨JLINK就可以搞定了!买个吧,好用的哇!一个定时器就可以控制4路频率独立,脉宽独立的PWM,4个定时器就可以控制16路!想怎么用都行的哇!

出0入0汤圆

发表于 2010-9-20 09:12:00 | 显示全部楼层
顶!

出0入0汤圆

发表于 2010-9-20 09:49:15 | 显示全部楼层
顶了,不过低频中这么做是没有问题的,但是高频率应该回有的延迟的,对于PWM精度高的东西可能有影响,或者是我多虑了.

出0入0汤圆

发表于 2010-9-20 11:07:22 | 显示全部楼层
顶,支持楼主共享。

出0入0汤圆

发表于 2010-9-20 11:44:34 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2010-9-20 12:36:07 | 显示全部楼层
好东西,MARK一下

出0入24汤圆

发表于 2010-9-20 13:05:55 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-20 22:54:45 | 显示全部楼层
试试DMA方式

出0入0汤圆

发表于 2010-9-20 23:33:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-20 23:45:19 | 显示全部楼层
在折腾STM32 TIM 指定脉冲个数输出(频率比较高MHZ级别)始终无结果的人路过

出0入90汤圆

 楼主| 发表于 2010-9-21 00:02:36 | 显示全部楼层
楼上厉害!MHZ,不敢想!

出0入0汤圆

发表于 2010-9-21 09:58:37 | 显示全部楼层
我看了程序,系统使用HSE的6倍频作为时钟,初始化SysTick时使用的8分频,重载计数9000,中断一次是1ms,由此推算使用的晶振是12MHz的,是吗?

出0入90汤圆

 楼主| 发表于 2010-9-21 10:37:26 | 显示全部楼层
楼上挺聪明的!!!

出0入0汤圆

发表于 2010-9-21 11:01:11 | 显示全部楼层
啊,我是想保证串口通信而准备换7.3728或11.0592MHz的晶振。

出0入0汤圆

发表于 2010-9-21 20:01:25 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-21 20:22:50 | 显示全部楼层
谢谢!

出0入0汤圆

发表于 2010-9-21 20:57:44 | 显示全部楼层
#include "stm32f10x_lib.h"

u32 TempK[3];        //产品唯一ID号
vu32 TempA;          //输入PWM的脉宽            
vu32 TempB;          //输入PWM的频率
vu32 TempC;          //PWM1输出频率
vu32 TempD;          //PWM1输出脉宽
vu32 TempE;          //PWM2频率
vu32 TempF;          //PWM2脉宽
vu32 TempG;          //PWM3频率
vu32 TempH;          //PWM3脉宽
vu32 TempI;          //PWM4频率
vu32 TempJ;          //PWM4脉宽

vu16 T1_H = 20000;
vu16 T1_L = 30000;
vu16 T2_H = 20000;
vu16 T2_L = 30000;
vu16 T3_H = 20000;
vu16 T3_L = 30000;
vu16 T4_H = 20000;
vu16 T4_L = 30000;

vu8 rx_flag;
vu8 tx_flag;
vu8 rx_buf[5];
vu8 tx_buf[10];
u8 rx_i,tx_i;
u8 ID_Check_Flag;
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_OCInitTypeDef  TIM_OCInitStructure;

u32 sys_frequency;

void ID_Write(void)
{
    u8 i;
    u32 temp = 0;       //ID以字位单位的和
    u16 res[3];         //存放余数
    for(i = 0;i < 3;i ++)
    {
        TempK = *(u32*)(0x1FFFF7E8 + 4 * i);
        temp += TempK;
    }
   
    res[0] = temp % 100;
    res[1] = temp % 500;
    res[2] = temp % 1000;
   
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    FLASH_ProgramHalfWord(0x0800f000,res[0]);
    FLASH_ProgramHalfWord(0x0800f900,res[1]);
    FLASH_ProgramHalfWord(0x0800fe00,res[2]);  
    FLASH_Lock();
}

void ID_Read(void)
{
    u8 i;
    u32 temp = 0;       //ID以字位单位的和
    u16 res[3];         //存放余数
    u32 read_buf[3];
    for(i = 0;i < 3;i ++)
    {
        TempK = *(u32*)(0x1FFFF7E8 + 4 * i);
        temp += TempK;
    }
   
    res[0] = temp % 100;
    res[1] = temp % 500;
    res[2] = temp % 1000;
   
    read_buf[0] = *(u32*)(0x0800f000) & 0xffff;
    read_buf[1] = *(u32*)(0x0800f900) & 0xffff;
    read_buf[2] = *(u32*)(0x0800fe00) & 0xffff;
   
    for(i = 0;i < 3;i ++)
    {
        if(res != (u16)(read_buf))
        {
            while(1);
        }
    }
}



void RCC_INIT(void)
{
        RCC_ClocksTypeDef RCC_Clocks;
    RCC_HSEConfig(RCC_HSE_ON);
    while(!RCC_WaitForHSEStartUp());                        //等待HSE发生作用
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    FLASH_SetLatency(FLASH_Latency_2);                      //最少1个等待,否则程序跑飞
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);
    RCC_PCLK2Config(RCC_HCLK_Div1);
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_6);     //6倍频
    RCC_PLLCmd(ENABLE);
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              //PLL时钟作为系统时钟源
   
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);        //必须先使能时钟,否则无法配置GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //必须先使能时钟,否则无法配置GPIO
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);     //开启TIM4时钟   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);     //开启TIM3时钟   
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);     //开启TIM3时钟     
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);   //开启USART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);     //开启TIM1时钟
   
        RCC_GetClocksFreq(&RCC_Clocks);
        sys_frequency = RCC_Clocks.SYSCLK_Frequency;
        sys_frequency /= 5;                                           
}

void NVIC_INIT(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    //开启串口中断
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
   
    //开启定时器2中断
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    //开启定时器3中断
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQChannel;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);   
   
   
}

void delays(u16 i)
{
        u32 j;
        for(;i > 0;i --)
                for(j = sys_frequency;j > 0;j--);
}



void GPIO_INIT(void)
{
        GPIO_InitTypeDef GPIO_InitStruct;
    //PWM输出
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    //PWM输入
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    //TX初始化
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    //RX初始化
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStruct);   
   
   
}


void TIM1_PWM_INIT(void)        //TIM1配置PWM输出参数
{
    u32 temp_fre,temp_duty;
    TempC = 60;                //设置频率初始值
    TempD = 4;                //设置初始占空比1 / 2
    temp_fre = (1000000 / TempC) - 1;
    temp_duty = ((temp_fre + 1) / TempD);
   
    TIM_TimeBaseStructure.TIM_Prescaler = 72;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period = temp_fre;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;   
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
   
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = temp_duty;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;   
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
   
    /* TIM1 counter enable */
    TIM_ARRPreloadConfig(TIM1, ENABLE);
    TIM_Cmd(TIM1, ENABLE);
   
    /* TIM1 Main Output Enable */
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
}


void TIM2_PWM_INIT(void)        
{
    TIM_TimeBaseStructure.TIM_Period = 65535;
    TIM_TimeBaseStructure.TIM_Prescaler = 71;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
   
    /* Output Compare Toggle Mode configuration: Channel1 */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = T1_H;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OC1Init(TIM2, &TIM_OCInitStructure);
   
    TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
   
    /* Output Compare Toggle Mode configuration: Channel2 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = T2_H;
   
    TIM_OC2Init(TIM2, &TIM_OCInitStructure);
   
    TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Disable);
   
    /* Output Compare Toggle Mode configuration: Channel3 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = T3_H;
   
    TIM_OC3Init(TIM2, &TIM_OCInitStructure);
   
    TIM_OC3PreloadConfig(TIM2, TIM_OCPreload_Disable);
   
    /* Output Compare Toggle Mode configuration: Channel4 */
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = T4_H;
   
    TIM_OC4Init(TIM2, &TIM_OCInitStructure);
   
    TIM_OC4PreloadConfig(TIM2, TIM_OCPreload_Disable);
   
    /* TIM enable counter */
    TIM_Cmd(TIM2, ENABLE);
   
    /* TIM IT enable */
    TIM_ITConfig(TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE);
}

void TIM3_PWM_IN_INIT(void)
{
    TIM_TimeBaseStructure.TIM_Period = 65535;
    TIM_TimeBaseStructure.TIM_Prescaler = 71;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
   
    TIM_ICInitTypeDef  TIM_ICInitStructure;   
    TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM_ICInitStructure.TIM_ICFilter = 0x0;
   
    TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);
    /* Select the TIM2 Input Trigger: TI2FP2 */
    TIM_SelectInputTrigger(TIM3, TIM_TS_TI2FP2);
   
    /* Select the slave Mode: Reset Mode */
    TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
   
    /* Enable the Master/Slave Mode */
    TIM_SelectMasterSlaveMode(TIM3, TIM_MasterSlaveMode_Enable);
   
    /* TIM enable counter */
    TIM_Cmd(TIM3, ENABLE);
   
    /* Enable the CC2 Interrupt Request */
    TIM_ITConfig(TIM3, TIM_IT_CC2, ENABLE);
}

void USART1_INIT(void)
{
    USART_InitTypeDef USART_InitStructure;
   
    USART_InitStructure.USART_BaudRate = 9600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
   
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
   
    USART_Cmd(USART1, ENABLE);
}

void SYS_TIM_INIT(void)
{
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    SysTick_SetReload(9000);                        //9MHZ下,计数9000就是1ms
    SysTick_CounterCmd(SysTick_Counter_Enable);     //使能systick计数器
    SysTick_ITConfig(ENABLE);                       //使能中断   
}

void sys_state_get(void)
{
    tx_buf[0] = TempB;
    tx_buf[1] = TempA;
    tx_buf[2] = TempC;
    tx_buf[3] = TempD;
    tx_buf[4] = TempE;
    tx_buf[5] = TempF;
    tx_buf[6] = TempG;
    tx_buf[7] = TempH;
    tx_buf[8] = TempI;
    tx_buf[9] = TempJ;
}

void system_init(void)
{
    TempA = 0;
    TempB = 0;
    TempC = 1000000 / 50000;
    TempD = T1_H / 1000;
    TempE = 1000000 / 50000;
    TempF = T2_H / 1000;
    TempG = 1000000 / 50000;
    TempH = T3_H / 1000;
    TempI = 1000000 / 50000;
    TempJ = T4_H / 1000;
}


int main(void)
{
    u32 main_temp;
        RCC_INIT();             //时钟配置
    NVIC_INIT();            //中断优先级配置
//    ID_Write();
    system_init();
        GPIO_INIT();            //IO口初始化        
    USART1_INIT();          //串口初始化,波特率9600,其他默认
    TIM2_PWM_INIT();        //TIM2的CH4通道输出PWM
    TIM3_PWM_IN_INIT();
    SYS_TIM_INIT();

        while (1)
        {
        if(rx_flag == 1)
        {
            rx_flag = 0;
            switch(rx_buf[1])
            {
            case 1:                         //修改通道1的频率,脉宽
                TempC = rx_buf[2];
                TempD = rx_buf[3];
                if((TempC > 17) && (TempC < 255))
                {
                    main_temp = 1000 / TempC;
                    if(main_temp > TempD)
                    {
                        T1_H = TempD * 1000;
                        T1_L = (main_temp - TempD) * 1000;
                    }
                }
                break;
            case 2:
                TempE = rx_buf[2];
                TempF = rx_buf[3];
                if((TempE > 17) && (TempE < 255))
                {
                    main_temp = 1000 / TempE;
                    if(main_temp > TempF)
                    {
                        T2_H = TempF * 1000;
                        T2_L = (main_temp - TempF) * 1000;
                    }
                }
                break;               
            case 3:
                TempG = rx_buf[2];
                TempH = rx_buf[3];
                if((TempG > 17) && (TempG < 255))
                {
                    main_temp = 1000 / TempG;
                    if(main_temp > TempH)
                    {
                        T3_H = TempH * 1000;
                        T3_L = (main_temp - TempH) * 1000;
                    }
                }
                break;               
            case 4:
                TempI = rx_buf[2];
                TempJ = rx_buf[3];
                if((TempI > 17) && (TempI < 255))
                {
                    main_temp = 1000 / TempI;
                    if(main_temp > TempJ)
                    {
                        T4_H = TempJ * 1000;
                        T4_L = (main_temp - TempJ) * 1000;
                    }
                }
                break;
            }
            USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);     //重新使能串口接收
        }
        }
}

/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name          : stm32f10x_it.c
* Author             : MCD Application Team
* Version            : V2.0.3
* Date               : 09/22/2008
* Description        : Main Interrupt Service Routines.
*                      This file provides template for all exceptions handler
*                      and peripherals interrupt service routine.
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_it.h"
u16 capture = 0;
extern vu16 T1_H;
extern vu16 T1_L;
extern vu16 T2_H;
extern vu16 T2_L;
extern vu16 T3_H;
extern vu16 T3_L;
extern vu16 T4_H;
extern vu16 T4_L;
extern vu32 TempA;          //输入PWM的脉宽            
extern vu32 TempB;          //输入PWM的频率
extern vu32 TempC;          //PWM1输出频率
extern vu32 TempD;          //PWM1输出脉宽
extern vu32 TempE;          //PWM2频率
extern vu32 TempF;          //PWM2脉宽
extern vu32 TempG;          //PWM3频率
extern vu32 TempH;          //PWM3脉宽
extern vu32 TempI;          //PWM4频率
extern vu32 TempJ;          //PWM4脉宽

extern vu8 rx_flag;
extern vu8 tx_flag;
extern vu8 rx_buf[5];
extern vu8 tx_buf[10];
extern u8 rx_i,tx_i;
extern u8 ID_Check_Flag;
extern void sys_state_get(void);

vu16 IC2Value = 0;
vu16 DutyCycle = 0;

* Function Name  : SysTickHandler
* Description    : This function handles SysTick Handler.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SysTickHandler(void)
{
    static u16 i;
    i++;
    if(i % 1000 == 0)           //1s钟串口发送一次当前的数据
    {
        sys_state_get();
        USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
    }
   
    if(i == 60000)
    {
        ID_Check_Flag = 1;
        i = 0;
    }
}

//*******************************************************************************
* Function Name  : TIM2_IRQHandler
* Description    : This function handles TIM2 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM2_IRQHandler(void)
{
    /* TIM2_CH1 toggling with frequency = 183.1 Hz */
    static u8 i1,i2,i3,i4;
    if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
    {
        i1++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC1 );
        capture = TIM_GetCapture1(TIM2);
        if(i1 % 2 == 1)
        {
            TIM_SetCompare1(TIM2, capture + T1_L);            
        }
        else
        {
            TIM_SetCompare1(TIM2, capture + T1_H);            
        }
    }

    /* TIM2_CH2 toggling with frequency = 366.2 Hz */
    if (TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
    {
        i2++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
        capture = TIM_GetCapture2(TIM2);
        if(i2 % 2 == 1)
        {
            TIM_SetCompare2(TIM2, capture + T2_L);            
        }
        else
        {
            TIM_SetCompare2(TIM2, capture + T2_H);            
        }
    }

    /* TIM2_CH3 toggling with frequency = 732.4 Hz */
    if (TIM_GetITStatus(TIM2, TIM_IT_CC3) != RESET)
    {
        i3++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
        capture = TIM_GetCapture3(TIM2);
        if(i3 % 2 == 1)
        {
            TIM_SetCompare3(TIM2, capture + T3_L);
        }
        else
        {
            TIM_SetCompare3(TIM2, capture + T3_H);
        }
    }

    /* TIM2_CH4 toggling with frequency = 1464.8 Hz */
    if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET)
    {
        i4++;
        TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
        capture = TIM_GetCapture4(TIM2);
        if(i4 % 2 == 1)
        {
            TIM_SetCompare4(TIM2, capture + T4_L);
        }
        else
        {
            TIM_SetCompare4(TIM2, capture + T4_H);
        }
    }
}

/*******************************************************************************
* Function Name  : TIM3_IRQHandler
* Description    : This function handles TIM3 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void TIM3_IRQHandler(void)
{
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    IC2Value = TIM_GetCapture2(TIM3);
   
    if (IC2Value != 0)
    {
        DutyCycle = (TIM_GetCapture1(TIM3) * 100) / IC2Value;   //占空比
        
        TempB = 1000000 / IC2Value;                             //输入PWM频率
        TempA = IC2Value / 1000;                                //输入PWM脉宽
    }
    else
    {
        DutyCycle = 0;
        TempB = 0;
        TempA = 0;
    }   
}

/

出0入0汤圆

发表于 2010-9-21 23:05:09 | 显示全部楼层
谢谢,很有用!

出0入0汤圆

发表于 2010-9-22 02:50:58 | 显示全部楼层
好東西!

出0入0汤圆

发表于 2011-1-21 21:06:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-6 18:35:06 | 显示全部楼层
学习

出0入0汤圆

发表于 2011-3-6 22:11:33 | 显示全部楼层
谢谢,正需要类似的东西

出0入0汤圆

发表于 2011-3-7 13:35:02 | 显示全部楼层
不知道最高PWM频率能上多少?

出0入0汤圆

发表于 2011-3-7 16:49:16 | 显示全部楼层
请问频率调节范围是多少?频率分辨率是多少?谢谢!

出0入0汤圆

发表于 2011-3-7 21:08:54 | 显示全部楼层
一个定时器  也可以做  不过精度 难以保证

出0入0汤圆

发表于 2011-3-9 14:31:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-11 11:27:04 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2011-3-24 16:30:30 | 显示全部楼层
谢谢楼主提醒,困扰我好久的问题在这找到答案。。。

出0入0汤圆

发表于 2011-3-24 19:37:16 | 显示全部楼层
mark

出0入31汤圆

发表于 2011-4-28 21:03:00 | 显示全部楼层
记号,挺有用

出0入90汤圆

 楼主| 发表于 2011-4-28 21:17:05 | 显示全部楼层
汗,那么久的帖子都被翻出来了啊!我STM32都快忘光了呢!哈哈!!!!

出0入0汤圆

发表于 2011-4-28 23:18:15 | 显示全部楼层
来,顶一个。。

出0入0汤圆

发表于 2011-4-29 14:31:17 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-4-30 15:44:38 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-3 17:29:16 | 显示全部楼层
学习。谢谢

出0入0汤圆

发表于 2011-5-6 20:16:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-18 11:13:26 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-5-19 12:04:01 | 显示全部楼层
弱弱的问个问题  TIM2的PWM输出不使能 PWM能出来么?

出0入0汤圆

发表于 2011-6-14 22:22:27 | 显示全部楼层
不太明白,一个定时器用比较模式输出4路PWM ,PWM频率不可调吧 只是脉宽可以调。比如用TIM1输出4路PWM  没法做到输出频率不同吧

出0入0汤圆

发表于 2011-7-26 16:14:06 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-26 20:48:05 | 显示全部楼层
顶!

出0入0汤圆

发表于 2011-9-2 09:48:58 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-9-2 10:13:50 | 显示全部楼层
顶!

出0入0汤圆

发表于 2011-9-10 18:36:07 | 显示全部楼层
楼主这么厉害啊~~~~~~~~~
还正打算买楼主几个LCD那呵呵~~~~~~
明天有时间就去拿一下呵呵

出0入0汤圆

发表于 2011-9-24 09:09:59 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-1 18:02:57 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-11-1 22:03:32 | 显示全部楼层
用比较模式进中断后重新置寄存器的方法就是中断太频繁了,尤其是频率比较高时及各路的占空比相互比较接近时,会不怎么准确了,但低频应该还不错及系统中没有别的高优先级的频繁中断。不用处理器中断干预的硬件PWM要想精确的频率可变及占空比可变,也只能每个定时器输入一路了,同一个定时器不需中断干预的只能输出多路频率相同但占空比可不能的PWM

出0入0汤圆

发表于 2011-11-1 22:03:43 | 显示全部楼层
用比较模式进中断后重新置寄存器的方法就是中断太频繁了,尤其是频率比较高时及各路的占空比相互比较接近时,会不怎么准确了,但低频应该还不错及系统中没有别的高优先级的频繁中断。不用处理器中断干预的硬件PWM要想精确的频率可变及占空比可变,也只能每个定时器输入一路了,同一个定时器不需中断干预的只能输出多路频率相同但占空比可不能的PWM

出0入0汤圆

发表于 2012-4-8 21:50:00 | 显示全部楼层
先留个名吧,50hz的信号应该比较准确吧...

出0入0汤圆

发表于 2012-4-9 10:05:26 | 显示全部楼层
看了资料但还是没有搞清楚STM32F103的PWM输出是固定到某个脚输出的还是可以任意定义输出?请高手明示!

出0入0汤圆

发表于 2012-5-17 19:52:31 | 显示全部楼层
学习 谢谢楼主

出0入0汤圆

发表于 2012-5-17 20:19:42 | 显示全部楼层
楼主可以看一下TIM中的TIM Base 例程,那里面就是一个定时器输出四个频率不同的PWM信号.

出0入0汤圆

发表于 2012-5-23 19:10:09 | 显示全部楼层
参照TIM中的TIM Base 例程,用STM32一个定时器输出4路频率、脉宽任意可调

出0入0汤圆

发表于 2012-9-14 09:51:05 | 显示全部楼层
你好,我是一个菜鸟,我想问你一下,输出频率在哪里修改,怎么修改?从串口接收到的数不是只改变占空比而已么?谢谢

出0入0汤圆

发表于 2012-9-14 10:21:56 | 显示全部楼层
mark                  

出0入0汤圆

发表于 2012-9-16 08:13:34 | 显示全部楼层
mark....................

出0入0汤圆

发表于 2012-9-16 08:45:10 | 显示全部楼层
很好 顶一个 mark

出0入0汤圆

发表于 2012-9-16 08:54:12 | 显示全部楼层
好东西!必须顶一个!

出0入0汤圆

发表于 2012-9-16 09:33:53 | 显示全部楼层
很好的资料,谢谢了!

出0入0汤圆

发表于 2012-9-16 17:15:31 | 显示全部楼层
多谢楼主分享,学习了

出0入0汤圆

发表于 2012-9-16 18:04:37 | 显示全部楼层
mark一个

出0入0汤圆

发表于 2012-11-1 11:55:02 | 显示全部楼层
请问如何能单独控制其中一个通道的开停

出0入0汤圆

发表于 2013-7-16 09:47:18 | 显示全部楼层
学习了,谢谢!

出0入0汤圆

发表于 2013-9-1 22:15:58 | 显示全部楼层
好东西!

出0入0汤圆

发表于 2014-3-6 20:20:23 | 显示全部楼层
Mark,值得钻研。

出0入0汤圆

发表于 2014-3-7 13:36:36 | 显示全部楼层
标记,stm32使用1个定时器实现4路PWM。

出0入0汤圆

发表于 2014-6-13 10:04:30 | 显示全部楼层
顶! 我也顶一个 我也顶一个

出0入0汤圆

发表于 2014-6-13 10:13:52 | 显示全部楼层
谢谢分享!好东西!

出0入0汤圆

发表于 2014-7-10 01:42:56 | 显示全部楼层
非常感谢!  虽然很早了

出0入0汤圆

发表于 2014-9-26 09:45:28 | 显示全部楼层
XUEXILE ~~~

出0入0汤圆

发表于 2014-9-26 13:59:36 | 显示全部楼层
楼主厉害,顶你

出0入0汤圆

发表于 2014-9-26 14:02:45 来自手机 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2014-10-7 11:00:12 | 显示全部楼层
不错,正要用到这个

出425入0汤圆

发表于 2014-10-7 11:06:54 | 显示全部楼层
正需要这个呢。顶你这样共享技术的好人。

出0入0汤圆

发表于 2014-10-7 11:11:15 来自手机 | 显示全部楼层
低频的pwm用用估计不错

出0入0汤圆

发表于 2014-10-7 11:12:44 | 显示全部楼层
bondxie3 发表于 2014-3-7 13:36
标记,stm32使用1个定时器实现4路PWM。

每个频率都不一样吗

出0入0汤圆

发表于 2014-10-7 11:14:00 | 显示全部楼层
lwg998 发表于 2012-4-9 10:05
看了资料但还是没有搞清楚STM32F103的PWM输出是固定到某个脚输出的还是可以任意定义输出?请高手明示! ...

固定的。
不同通道对应不同的pin。

出0入0汤圆

发表于 2014-10-7 14:36:57 | 显示全部楼层

谢谢分享!顶一个!

出0入0汤圆

发表于 2014-10-7 15:57:19 | 显示全部楼层
谢谢LZ分享

出0入0汤圆

发表于 2014-10-9 08:18:20 | 显示全部楼层
想问一下大神是不是用keil写的啊??

出0入0汤圆

发表于 2014-10-9 08:53:52 | 显示全部楼层
本帖最后由 cf5257 于 2014-10-9 08:57 编辑

首先感谢楼主的分享,看到程序中读取验证唯一ID的代码,请问楼主是用来上位机绑定特定下位机?

void ID_Write(void)
{
    u8 i;
    u32 temp = 0;       //ID以字位单位的和
    u16 res[3];         //存放余数
    for(i = 0;i < 3;i ++)
    {
        TempK = *(u32*)(0x1FFFF7E8 + 4 * i);
        temp += TempK;
    }
   
    res[0] = temp % 100;
    res[1] = temp % 500;
    res[2] = temp % 1000;
   
    FLASH_Unlock();
    FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
    FLASH_ProgramHalfWord(0x0800f000,res[0]);
    FLASH_ProgramHalfWord(0x0800f900,res[1]);
    FLASH_ProgramHalfWord(0x0800fe00,res[2]);  
    FLASH_Lock();
}

void ID_Read(void)
{
    u8 i;
    u32 temp = 0;       //ID以字位单位的和
    u16 res[3];         //存放余数
    u32 read_buf[3];
    for(i = 0;i < 3;i ++)
    {
        TempK = *(u32*)(0x1FFFF7E8 + 4 * i);
        temp += TempK;
    }
   
    res[0] = temp % 100;
    res[1] = temp % 500;
    res[2] = temp % 1000;
   
    read_buf[0] = *(u32*)(0x0800f000) & 0xffff;
    read_buf[1] = *(u32*)(0x0800f900) & 0xffff;
    read_buf[2] = *(u32*)(0x0800fe00) & 0xffff;
   
    for(i = 0;i < 3;i ++)
    {
        if(res != (u16)(read_buf))
        {
            while(1);
        }
    }
}

出0入0汤圆

发表于 2014-10-9 08:58:23 | 显示全部楼层
caccjt 发表于 2014-10-9 08:18
想问一下大神是不是用keil写的啊??

IAR环境的项目

出0入0汤圆

发表于 2014-10-9 09:02:25 | 显示全部楼层
cf5257 发表于 2014-10-9 08:53
首先感谢楼主的分享,看到程序中读取验证唯一ID的代码,请问楼主是用来上位机绑定特定下位机?

void ID_Wri ...

    for(i = 0;i < 3;i ++)
    {
        if(res != (u16)(read_buf))//这句真没看明白
        {
            while(1);
        }
    }

出0入90汤圆

 楼主| 发表于 2014-10-9 11:24:40 | 显示全部楼层
cf5257 发表于 2014-10-9 09:02
for(i = 0;i < 3;i ++)
    {
        if(res != (u16)(read_buf))//这句真没看明白

不好意思!几年前的东西了,我也忘记是什么意思了!

出0入0汤圆

发表于 2014-10-9 15:59:52 | 显示全部楼层
顶楼主顶顶顶顶顶

出0入8汤圆

发表于 2014-10-10 15:43:23 | 显示全部楼层
非常感谢楼主~

出0入13汤圆

发表于 2014-10-10 16:52:41 | 显示全部楼层
非常感谢楼主
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-27 02:54

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表