STM32F767的PWM驱动实现

1 简介

1.1 PWM介绍

      脉冲宽度调制PWM,是英文“Pulse Width Modulation的缩写,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。PWM本质就是对脉冲宽度的控制,其脉冲宽度在整个周期中所占的比例被称为“占空比”。

1.2 STM32F767的PWM介绍

      STM32F767 的定时器除了 TIM6 和 7,其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。主要寄存器包括控制寄存器(TIMxCR)、计数器(TIMxCNT)、预分频器(TIMxPSC)、自动重载寄存器(TIMxARR)、比较寄存器(TIMxCCR)。PWM输出频率由PSC和ARR决定,占空比体现为CCR与ARR的比值。基本原理如图 1.1所示。

                                   图 1.1 PWM原理示意图

这四个定时器所接的时钟总线并不一致,其中TIM10、11接在APB2上,TIM13、14接在APB1上,如图 1.2所示。

                                                             图 1.2 定时器时钟框图

本驱动主要实现TIM10、TIM11、TIM13、TIM14四路PWM波的初始化与参数配置接口。

2 接口设计

      TIM10、TIM11、TIM13、TIM14四路PWM对应四个设备文件/dev/pwm0、/dev/pwm1、/dev/pwm2、/dev/pwm3。驱动中将ARR固定配置为2500不可修改,通过ioctl配置PSC和CCR设置频率与占空比。命令105配置参数PSC,命令106配置CCR,计算公式如下(APB1总线桥108000000Hz,APB2总线桥216000000Hz):

TIM10、TIM11

频率(Hz) = 216000000  / 2500 / (PSC + 1)   (可配置范围1.3~86400Hz)

占空比(%)= (CCR + 1)/ 2500               (可配置范围0~100%)

TIM13、TIM14

频率(Hz) = 108000000  / 2500 / (PSC + 1)   (可配置范围0.66~43200Hz)

占空比(%)= (CCR + 1)/ 2500               (可配置范围0~100%)

      

       应用程序例程如程序清单 2.1所示。

                                                                     程序清单 2.1 PWM应用例程

int  main (void)

{

    int fd, fd1;

    fd = open("/dev/pwm0", O_RDWR);

    if (fd < 0) {

        perror("open");

        exit(PX_ERROR);

    }

    /*

    **           PWM0、PWM1频率设置:

    **           频率(Hz)= 216000000 / 2500 / (uiPsc + 1)

    **                     = 216000000 / 2500 / (287 + 1)

    **                     = 300Hz

    */

    ioctl(fd, 105, 287);

    /*

     * 占空比50%

     */

    ioctl(fd, 106, 1250);

 

    fd1 = open("/dev/pwm3", O_RDWR);

    if (fd < 0) {

        perror("open");

        exit(PX_ERROR);

    }

    /*

    **           PWM2、PWM3频率设置:

    **           频率(Hz)= 216000000 / 2 / 2500 / (uiPsc + 1)

    **                     = 216000000 / 2 / 2500 / (143 + 1)

    **                     = 300Hz

    */

    ioctl(fd1, 105, 143);

    /*

     * 占空比25%

     */

    ioctl(fd, 106, 625);

    sleep(52);

    close(fd);

    close(fd1);

    return  (0);

}

3 驱动设计

      PWM驱动为字符设备驱动,主要实现了open、close、ioctl三个接口。使用ST提供的Hal库函数避免了直接操作具体的寄存器,目前使用1.2版本Hal库。

3.1 open

      open中主要对指定的pwm定时器进行初始化操作,即调用__timPwmInit()。初始化内容包括引脚初始化、定时器初始化和通道初始化三个部分。默认配置占空比50%。__timPwmInit()具体实现如程序清单 3.1所示。

                                                            程序清单 3.1 pwm初始化操作

/*********************************************************************************************************

** 函数名称: __timPwmInit

** 功能描述: pwm初始化

** 输  入  : uiIndex             PWM 设备控制器序号

** 输  出  : NONE

** 返  回  : ERROR_CODE

*********************************************************************************************************/

static void __timPwmInit (INT  uiIndex)

{

    GPIO_InitTypeDef GPIO_Initure;

 

    if (uiIndex < 0 || uiIndex >= HW_PWM_MAX) {

        printk(KERN_ERR "%s: pwm index invalid!\n", __func__);

        return;

    }

 

    switch (uiIndex) {

    case HW_PWM0:

        __HAL_RCC_TIM10_CLK_ENABLE();                                                                     /* 使能定时器10                           */

        __HAL_RCC_GPIOF_CLK_ENABLE();                                                                    /* 开启GPIOF时钟                        */

        GPIO_Initure.Pin        = GPIO_PIN_6;                                                                       /* PF6                                          */

        GPIO_Initure.Mode      = GPIO_MODE_AF_PP;                                                       /* 复用推完输出                            */

        GPIO_Initure.Pull        = GPIO_PULLDOWN;                                                            /* 上拉                                          */

        GPIO_Initure.Speed      = GPIO_SPEED_HIGH;                                                      /* 高速                                            */

        GPIO_Initure.Alternate    = GPIO_AF3_TIM10;                                                        /* PF6 复用为TIM10                       */

        HAL_GPIO_Init(GPIOF, &GPIO_Initure);

 

        _G_timHandler[uiIndex].Instance          = TIM10;                                                      /* 定时器10                                     */

        _G_timHandler[uiIndex].Init.Prescaler      = PWM_PSC_DEFAULT;                           /* 定时器分频                                 */

        _G_timHandler[uiIndex].Init.CounterMode  = TIM_COUNTERMODE_UP;                  /* 向上计数模式                              */

        _G_timHandler[uiIndex].Init.Period        = PWM_ARR_DEFAULT;                              /* 自动重装载值                              */

        _G_timHandler[uiIndex].Init.ClockDivision  = TIM_CLOCKDIVISION_DIV1;

 

        _G_timChannel[uiIndex].OCMode         = TIM_OCMODE_PWM1;                            /* 模式选择PWM1                            */

        _G_timChannel[uiIndex].Pulse            = PWM_ARR_DEFAULT / 2;

                                                                                                                                         /* 设置比较值,此值用来确定占空比   */

                                                                                                                                          /* 默认比较值为自动重装载值的一   */

                                                                                                                                          /* 半,即占空比为50%                       */

        _G_timChannel[uiIndex].OCPolarity       = TIM_OCPOLARITY_HIGH;

                                                                                                                                          /* 输出比较极性为高                        */

        break;

    case HW_PWM1:

        __HAL_RCC_TIM11_CLK_ENABLE();                                                                       /* 使能定时器11                               */

        __HAL_RCC_GPIOF_CLK_ENABLE();                                                                      /* 开启GPIOF时钟                           */

        GPIO_Initure.Pin        = GPIO_PIN_7;                                                                        /* PF7                                              */

        GPIO_Initure.Mode      = GPIO_MODE_AF_PP;                                                        /* 复用推完输出                                */

        GPIO_Initure.Pull       = GPIO_PULLDOWN;                                                              /* 上拉                                              */

        GPIO_Initure.Speed      = GPIO_SPEED_HIGH;                                                        /* 高速                                               */

        GPIO_Initure.Alternate   = GPIO_AF3_TIM11;                                                           /* PF7 复用为TIM11                          */

        HAL_GPIO_Init(GPIOF, &GPIO_Initure);

 

        _G_timHandler[uiIndex].Instance          = TIM11;                                                        /* 定时器11                                       */

        _G_timHandler[uiIndex].Init.Prescaler      = PWM_PSC_DEFAULT;                            /* 定时器分频                                    */

        _G_timHandler[uiIndex].Init.CounterMode  = TIM_COUNTERMODE_UP;                  /* 向上计数模式                                 */

        _G_timHandler[uiIndex].Init.Period        = PWM_ARR_DEFAULT;                              /* 自动重装载值                                 */

        _G_timHandler[uiIndex].Init.ClockDivision  = TIM_CLOCKDIVISION_DIV1;

 

        _G_timChannel[uiIndex].OCMode         = TIM_OCMODE_PWM1;                             /* 模式选择PWM1                              */

        _G_timChannel[uiIndex].Pulse            = PWM_ARR_DEFAULT / 2;

                                                                                                                                          /* 设置比较值,此值用来确定占空比   */

                                                                                                                                          /* 默认比较值为自动重装载值的一    */

                                                                                                                                            /* 半,即占空比为50%                */

        _G_timChannel[uiIndex].OCPolarity       = TIM_OCPOLARITY_HIGH;

                                                                                                                                          /* 输出比较极性为高                  */

        break;

    case HW_PWM2:

        __HAL_RCC_TIM13_CLK_ENABLE();                                                                      /* 使能定时器13                          */

        __HAL_RCC_GPIOF_CLK_ENABLE();                                                                     /* 开启GPIOF时钟                       */

        GPIO_Initure.Pin        = GPIO_PIN_8;                                                                       /* PF8                                          */

        GPIO_Initure.Mode      = GPIO_MODE_AF_PP;                                                       /* 复用推完输出                            */

        GPIO_Initure.Pull       = GPIO_PULLDOWN;                                                             /* 上拉                                          */

        GPIO_Initure.Speed      = GPIO_SPEED_HIGH;                                                        /* 高速                                         */

        GPIO_Initure.Alternate   = GPIO_AF9_TIM13;                                                          /* PF8 复用为TIM13                     */

        HAL_GPIO_Init(GPIOF, &GPIO_Initure);

 

        _G_timHandler[uiIndex].Instance          = TIM13;                                                      /* 定时器13                                   */

        _G_timHandler[uiIndex].Init.Prescaler      = PWM_PSC_DEFAULT;                          /* 定时器分频                                 */

        _G_timHandler[uiIndex].Init.CounterMode  = TIM_COUNTERMODE_UP;                /* 向上计数模式                              */

        _G_timHandler[uiIndex].Init.Period        = PWM_ARR_DEFAULT;                             /* 自动重装载值                             */

        _G_timHandler[uiIndex].Init.ClockDivision  = TIM_CLOCKDIVISION_DIV1;

 

        _G_timChannel[uiIndex].OCMode         = TIM_OCMODE_PWM1;                           /* 模式选择PWM1                           */

        _G_timChannel[uiIndex].Pulse            = PWM_ARR_DEFAULT / 2;

                                                                                                                                        /* 设置比较值,此值用来确定占空比  */

                                                                                                                                       /* 默认比较值为自动重装载值的一    */

                                                                                                                                        /* 半,即占空比为50%                       */

        _G_timChannel[uiIndex].OCPolarity       = TIM_OCPOLARITY_HIGH;

                                                                                                                                       /* 输出比较极性为高                         */

        break;

    case HW_PWM3:

        __HAL_RCC_TIM14_CLK_ENABLE();                                                                   /* 使能定时器14                                 */

        __HAL_RCC_GPIOF_CLK_ENABLE();                                                                  /* 开启GPIOF时钟                              */

        GPIO_Initure.Pin        = GPIO_PIN_9;                                                                     /* PF9                                                 */

        GPIO_Initure.Mode      = GPIO_MODE_AF_PP;                                                      /* 复用推完输出                                 */

        GPIO_Initure.Pull       = GPIO_PULLDOWN;                                                             /* 上拉                                               */

        GPIO_Initure.Speed      = GPIO_SPEED_HIGH;                                                       /* 高速                                               */

        GPIO_Initure.Alternate   = GPIO_AF9_TIM14;                                                         /* PF9 复用为TIM14                          */

        HAL_GPIO_Init(GPIOF, &GPIO_Initure);

 

        _G_timHandler[uiIndex].Instance          = TIM14;                                                     /* 定时器14                                        */

        _G_timHandler[uiIndex].Init.Prescaler      = PWM_PSC_DEFAULT;                          /* 定时器分频                                    */

        _G_timHandler[uiIndex].Init.CounterMode  = TIM_COUNTERMODE_UP;                /* 向上计数模式                                  */

        _G_timHandler[uiIndex].Init.Period        = PWM_ARR_DEFAULT;                             /* 自动重装载值                                  */

        _G_timHandler[uiIndex].Init.ClockDivision  = TIM_CLOCKDIVISION_DIV1;

 

        _G_timChannel[uiIndex].OCMode         = TIM_OCMODE_PWM1;                           /* 模式选择PWM1                               */

        _G_timChannel[uiIndex].Pulse            = PWM_ARR_DEFAULT / 2;

                                                                                                                                        /* 设置比较值,此值用来确定占空比      */

                                                                                                                                         /* 默认比较值为自动重装载值的一      */

                                                                                                                                         /* 半,即占空比为50%                          */

        _G_timChannel[uiIndex].OCPolarity       = TIM_OCPOLARITY_HIGH;

                                                                                                                                         /* 输出比较极性为高                          */

        break;

    default:

        printk(KERN_ERR "__timPwmInit(): uiIndex Invalid!\n");

        return;

        break;

    }

 

    HAL_TIM_PWM_Init(&_G_timHandler[uiIndex]);                                                             /* 初始化PWM                       */

    HAL_TIM_PWM_ConfigChannel(&_G_timHandler[uiIndex],

                              &_G_timChannel[uiIndex],

                               TIM_CHANNEL_1);                                                                             /* 配置通道                            */

    HAL_TIM_PWM_Start(&_G_timHandler[uiIndex], TIM_CHANNEL_1);                            /* 开启PWM通道                    */

}

 

3.2 close

      close操作主要就是关闭PWM波的输出,如程序清单 3.2所示。

                                                                  程序清单 3.2 close操作

/*********************************************************************************************************

** 函数名称: __pwmClose

** 功能描述: 关闭 PWM 设备

** 输  入  : pFdEntry              文件结构

** 输  出  : NONE

** 返  回  : ERROR_CODE

*********************************************************************************************************/

static INT  __pwmClose (PLW_FD_ENTRY   pFdEntry)

{

    __PPWM_CONTROLER  pPwmDev = (__PPWM_CONTROLER)pFdEntry->FDENTRY_pdevhdrHdr;

    UINT              uiIndex = pPwmDev->PWMC_uiIndex;

 

    HAL_TIM_PWM_Stop(&_G_timHandler[uiIndex],TIM_CHANNEL_1);            /* 关闭PWM通道                  */

    LW_DEV_DEC_USE_COUNT(&pPwmDev->PWMC_devHdr);

 

    return (PX_ERROR);

}

3.3 ioctl

      ioctl操作主要通过接口__timPwmPrescaleSet()、__timPwmDutySet()配置PSC、CCR两个寄存器,用于设置频率与占空比,如程序清单 3.3所示。

                                                         程序清单 3.3 频率、占空比配置

/*********************************************************************************************************

** 函数名称: __timPwmPrescaleSet

** 功能描述: pwm预分频设置

**           PWM0/1与PWM2/3频率计算方式不一样,这与技术手册不一致,疑似硬件BUG

**           PWM0、PWM1频率设置:

**           频率(Hz)= 216000000 / 2500 / (uiPsc + 1)

**           PWM2、PWM3频率设置:

**           频率(Hz)= 216000000 / 2 / 2500 / (uiPsc + 1)

** 输  入  : uiIndex             PWM 设备控制器序号

** 输  出  : NONE

** 返  回  : ERROR_CODE

*********************************************************************************************************/

static void __timPwmPrescaleSet (INT  uiIndex, UINT16  uiPsc)

{

    if (uiIndex < 0 || uiIndex >= HW_PWM_MAX) {

        printk(KERN_ERR "%s: pwm index invalid!\n", __func__);

        return;

    }

 

    _G_timHandler[uiIndex].Init.Prescaler      = uiPsc;                                              /* 频率(Hz) = 216000000                 */

                                                                                                                              /*     / (PWM_ARR_DEFAULT + 1)    */

                                                                                                                              /*     / (uiPsc + 1)                              */

 

    HAL_TIM_PWM_Init(&_G_timHandler[uiIndex]);                                                /* 初始化PWM                                   */

    HAL_TIM_PWM_ConfigChannel(&_G_timHandler[uiIndex],

                              &_G_timChannel[uiIndex],

                               TIM_CHANNEL_1);                                                                /* 配置通道                                        */

    HAL_TIM_PWM_Start(&_G_timHandler[uiIndex], TIM_CHANNEL_1);               /* 开启PWM通道                                */

}

 

/*********************************************************************************************************

** 函数名称: __timPwmDutySet

** 功能描述: pwm占空比设置

**           占空比(%)= uiDuty / (2500 - 1)

** 输  入  : uiIndex             PWM 设备控制器序号

** 输  出  : NONE

** 返  回  : ERROR_CODE

*********************************************************************************************************/

static void __timPwmDutySet (INT  uiIndex, UINT16  uiDuty)

{

    if (uiIndex < 0 || uiIndex >= HW_PWM_MAX) {

        printk(KERN_ERR "%s: pwm index invalid!\n", __func__);

        return;

    }

    if (uiDuty > PWM_ARR_DEFAULT) {

        printk(KERN_ERR "%s: pwm Duty invalid!\n", __func__);

        return;

    }

 

    _G_timChannel[uiIndex].Pulse  = uiDuty;                                                   /* 占空比(%) = uiDuty                       */

                                                                                                                      /*             / PWM_ARR_DEFAULT    */

 

    HAL_TIM_PWM_Init(&_G_timHandler[uiIndex]);                                         /* 初始化PWM                                  */

    HAL_TIM_PWM_ConfigChannel(&_G_timHandler[uiIndex],

                              &_G_timChannel[uiIndex],

                               TIM_CHANNEL_1);                                                          /* 配置通道                                      */

    HAL_TIM_PWM_Start(&_G_timHandler[uiIndex], TIM_CHANNEL_1);         /* 开启PWM通道                              */

}

 

 

STM32F767单片机开发板实验例程HAL库版本60个软件工程源码合集: STM32F7开发指南-HAL库版本_V1.1.pdf 实验0-1 Template工程模板-新建工程章节使用 实验0-2 Template工程模板-调试章节使用 实验0-3 Template工程模板-使用STM32CubeMX配置 实验1 跑马灯实验 实验10 电容触摸按键实验 实验11 OLED显示实验 实验12 内存保护(MPU)实验 实验13 TFTLCD(MCU屏)实验 实验14 SDRAM实验 实验15 LTDC LCD(RGB屏)实验 实验16 USMART调试试验 实验17 RTC实时时钟实验 实验18 随机数发生器实验 实验19 待机唤醒实验 实验2 按键输入实验 实验20 ADC实验 实验21 内部温度传感器实验 实验22 DAC实验 实验23 PWM DAC实验 实验24 DMA实验 实验25 IIC实验 实验26 IO扩展实验 实验27 光照&接近传感器实验 实验28 QSPI实验 实验29 485实验 实验3 串口通信实验 实验30 CAN实验 实验31 触摸屏实验 实验32 红外遥控实验 实验33 DS18B20数字温度传感器实验 实验34 DHT11数字温湿度传感器实验 实验35 MPU9250九轴传感器实验 实验36 NRF24L01无线通信实验 实验37 FLASH模拟EEPROM实验 实验38 摄像头实验 实验39 内存管理实验 实验4 外部中断实验 实验40 SD卡实验 实验41 NAND FLASH实验 实验42 FATFS实验 实验43 汉字显示实验 实验44 图片显示实验 实验45 硬件JPEG解码实验 实验46 照相机实验 实验47 音乐播放器实验 实验48 录音机实验 实验49 SPDIF(光纤音频)实验 实验5 独立看门狗实验 实验50 视频播放器实验 实验51 FPU测试(Julia分形)实验 实验52 DSP测试实验 实验53 手写识别实验 实验54 T9拼音输入法实验 实验55 串口IAP实验 实验56 USB读卡器(Slave)实验 实验57 USB声卡(Slave)实验 实验58 USB虚拟串口(Slave)实验 实验59 USB U盘(Host)实验 实验6 窗口看门狗实验 实验60 USB鼠标键盘(Host)实验 实验61 网络通信实验 实验62 UCOSII实验1-1-任务调度 实验62 UCOSII实验1-2-任务创建删除挂起恢复 实验63 UCOSII实验2-信号量和邮箱 实验64 UCOSII实验3-消息队列、信号量和软件定时器 实验7 定时器中断实验 实验8 PWM输出实验 实验9 输入捕获实验
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stone8761

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值