[原创] FRDM-KW41Z入门——PWM驱动舵机

dql2016   2017-5-4 21:10 楼主
舵机型号:SM-S4306R
采用周期为20ms的PWM驱动,PWM脉宽在0.5ms-2.5ms之间;
舵机5V工作电压,电流80mA左右,板卡输出3.3V可直接驱动起来;
定时器时钟为40MHz/8=5MHz,使用PTM1的通道1作为PWM的输出通道,对应GPIO为PTA1;
脉宽为0.5ms~1.5ms时正转,值越小,旋转速度越大;
脉宽为1.5ms~2.5ms为反转,值越大,旋转速度越大;
脉宽为1.5ms时停止,实际不确定,例如可能是1510us;

搜狗截图20170504204908.png

搜狗截图20170504204954.png

在例程SDK_2.2_FRDM-KW41Z\boards\frdmkw41z\driver_examples\tpm\simple_pwm基础修改;
修改后pin_mux.c文件如下:

  1. #include "fsl_common.h"
  2. #include "fsl_port.h"
  3. #include "pin_mux.h"

  4. #define PIN6_IDX                         6u   /*!< Pin number for pin 6 in a port */
  5. #define PIN7_IDX                         7u   /*!< Pin number for pin 7 in a port */
  6. #define PIN1_IDX                       1u   /*!< Pin number for pin 1 in a port */
  7. #define SOPT4_TPM1CH1SRC_TPM          00   /*!< TPM1 Channel 1 Input Capture Source Select: TPM1_CH1 signal */
  8. #define SOPT5_LPUART0RXSRC_LPUART_RX  0x00u   /*!< LPUART0 Receive Data Source Select: LPUART_RX pin */

  9. /*
  10. * TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL *****************************
  11. BOARD_InitPins:
  12. - options: {coreID: singlecore, enableClock: 'true'}
  13. - pin_list:
  14.   - {pin_num: '42', peripheral: LPUART0, signal: RX, pin_signal: TSI0_CH2/PTC6/LLWU_P14/XTAL_OUT_EN/I2C1_SCL/UART0_RX/TPM2_CH0/BSM_FRAME}
  15.   - {pin_num: '43', peripheral: LPUART0, signal: TX, pin_signal: TSI0_CH3/PTC7/LLWU_P15/SPI0_PCS2/I2C1_SDA/UART0_TX/TPM2_CH1/BSM_DATA}
  16.   - {pin_num: '6', peripheral: TPM2, signal: 'CH, 0', pin_signal: TSI0_CH12/PTA18/LLWU_P6/SPI1_SCK/TPM2_CH0}
  17. * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL ***
  18. */

  19. /*FUNCTION**********************************************************************
  20. *
  21. * Function Name : BOARD_InitPins
  22. * Description   : Configures pin routing and optionally pin electrical features.
  23. *
  24. *END**************************************************************************/
  25. void BOARD_InitPins(void) {
  26.   CLOCK_EnableClock(kCLOCK_PortA);                           /* Port A Clock Gate Control: Clock enabled */
  27.   CLOCK_EnableClock(kCLOCK_PortC);                           /* Port C Clock Gate Control: Clock enabled */

  28.   PORT_SetPinMux(PORTA, PIN1_IDX, kPORT_MuxAlt5);           /* PORTA18 (pin 6) is configured as TPM1_CH1 */
  29.   PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt4);            /* PORTC6 (pin 42) is configured as UART0_RX */
  30.   PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt4);            /* PORTC7 (pin 43) is configured as UART0_TX */
  31.   SIM->SOPT4 = ((SIM->SOPT4 &
  32.     (~(SIM_SOPT4_TPM1CLKSEL_MASK)))                          /* Mask bits to zero which are setting */
  33.       | SIM_SOPT4_TPM1CLKSEL(SOPT4_TPM1CH1SRC_TPM)           /* TPM1 Channel 1 Input Capture Source Select: TPM1_CH1 signal */
  34.     );
  35.   SIM->SOPT5 = ((SIM->SOPT5 &
  36.     (~(SIM_SOPT5_LPUART0RXSRC_MASK)))                        /* Mask bits to zero which are setting */
  37.       | SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX) /* LPUART0 Receive Data Source Select: LPUART_RX pin */
  38.     );
  39. }


  40. main.c修改后如下:

  41. #include "fsl_debug_console.h"
  42. #include "board.h"
  43. #include "fsl_tpm.h"

  44. #include "pin_mux.h"
  45. /*******************************************************************************
  46. * Definitions
  47. ******************************************************************************/
  48. #define BOARD_TPM_BASEADDR TPM1
  49. #define BOARD_TPM_CHANNEL 1U

  50. /* Interrupt to enable and flag to read; depends on the TPM channel used */
  51. #define TPM_CHANNEL_INTERRUPT_ENABLE kTPM_Chnl0InterruptEnable
  52. #define TPM_CHANNEL_FLAG kTPM_Chnl0Flag

  53. /* Interrupt number and interrupt handler for the TPM instance used */
  54. #define TPM_INTERRUPT_NUMBER TPM1_IRQn
  55. #define TPM_LED_HANDLER TPM1_IRQHandler

  56. /* Get source clock for TPM driver */
  57. #define TPM_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_McgFllClk)

  58. /*******************************************************************************
  59. * Prototypes
  60. ******************************************************************************/
  61. /*!
  62. * @brief delay a while.
  63. */
  64. void delay(void);

  65. /*******************************************************************************
  66. * Variables
  67. ******************************************************************************/
  68. volatile bool brightnessUp = true; /* Indicate LED is brighter or dimmer */
  69. volatile uint8_t updatedDutycycle = 10U;
  70. volatile uint8_t getCharValue = 0U;

  71. /*******************************************************************************
  72. * Code
  73. ******************************************************************************/
  74. /*!
  75. * @brief Main function
  76. */
  77. int main(void)
  78. {
  79.     tpm_config_t tpmInfo;
  80.     tpm_chnl_pwm_signal_param_t tpmParam;
  81.     tpm_pwm_level_select_t pwmLevel = kTPM_HighTrue;

  82.     /* Configure tpm params with frequency 24kHZ */
  83.     tpmParam.chnlNumber = (tpm_chnl_t)BOARD_TPM_CHANNEL;
  84.     tpmParam.level = pwmLevel;
  85.     tpmParam.dutyCyclePercent = updatedDutycycle;

  86.     /* Board pin, clock, debug console init */
  87.     BOARD_InitPins();
  88.     BOARD_BootClockRUN();
  89.     BOARD_InitDebugConsole();

  90.     /* Select the clock source for the TPM counter as MCGPLLCLK */
  91.     CLOCK_SetTpmClock(1U);
  92.         
  93.                 PRINTF("\r\n CoreSysClk=%d MHz\r\n",CLOCK_GetFreq(kCLOCK_CoreSysClk)/1000000);
  94. //                PRINTF("\r\n PlatClk=%d MHz\r\n",CLOCK_GetFreq(kCLOCK_PlatClk)/1000000);
  95. //                PRINTF("\r\n BusClk=%d MHz\r\n",CLOCK_GetFreq(kCLOCK_BusClk)/1000000);
  96. //                PRINTF("\r\n FlashClk=%d MHz\r\n",CLOCK_GetFreq(kCLOCK_FlashClk)/1000000);
  97. //                PRINTF("\r\n Er32kClk=%d MHz \r\n",CLOCK_GetFreq(kCLOCK_Er32kClk)/1000000);
  98. //                PRINTF("\r\n Osc0ErClk=%d MHz \r\n",CLOCK_GetFreq(kCLOCK_Osc0ErClk)/1000000);
  99. //                PRINTF("\r\n McgInternalRefClk=%d MHz \r\n",CLOCK_GetFreq(kCLOCK_McgInternalRefClk)/1000000);
  100.                 PRINTF("\r\n McgFllClk=%d MHz \r\n",CLOCK_GetFreq(kCLOCK_McgFllClk)/1000000);
  101. //                PRINTF("\r\n LpoClk=%d MHz \r\n",CLOCK_GetFreq(kCLOCK_LpoClk)/1000000);
  102.         
  103.     /* Print a note to terminal */
  104.     PRINTF("\r\nTPM example to output center-aligned PWM signal\r\n");
  105.     PRINTF("\r\nIf an LED is connected to the TPM pin, you will see a change in LED brightness if you enter different values");
  106.     PRINTF("\r\nIf no LED is connected to the TPM pin, then probe the signal using an oscilloscope");

  107.     TPM_GetDefaultConfig(&tpmInfo);
  108.                 tpmInfo.prescale=kTPM_Prescale_Divide_8;//40MHz/8
  109.     /* Initialize TPM module */
  110.     TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo);

  111.     if(kStatus_Success!=TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, 50, TPM_SOURCE_CLOCK))
  112.                 {
  113.                  PRINTF("\r\n SetupPwm Error! \r\n");
  114.                 }

  115.     TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock);

  116.     while (1)
  117.     {
  118.         do
  119.         {
  120.             PRINTF("\r\nPlease enter a value to update the Duty cycle:\r\n");
  121.             PRINTF("Note: The range of value is 0 to 9.\r\n");
  122.             PRINTF("For example: If enter '5', the duty cycle will be set to 50 percent.\r\n");
  123.             PRINTF("Value:");
  124.             getCharValue = GETCHAR() - 0x30U;
  125.             PRINTF("%d", getCharValue);
  126.             PRINTF("\r\n");
  127.         } while (getCharValue > 9U);

  128.         updatedDutycycle = getCharValue ;//20ms左右的脉冲,高电平0.5ms~1.5ms(updatedDutycycle为2.5~7.5)正转,值越小,旋转速度越大;1.5ms~2.5ms(updatedDutycycle为7.5~12.5)为反转,值越大,旋转速度越大;

  129.         /* Disable channel output before updating the dutycycle */
  130.       //  TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, 0U);

  131.         /* Update PWM duty cycle */
  132.         TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, kTPM_CenterAlignedPwm,updatedDutycycle);

  133.         /* Start channel output with updated dutycycle */
  134.        // TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, pwmLevel);

  135.         PRINTF("The duty cycle was successfully updated!\r\n");
  136.     }
  137. }


控制舵机还是很精确的:
IMG_20170504_203053.jpg

另外试了下,频率可达到1M:
IMG_20170504_204506.jpg

此内容由EEWORLD论坛网友dql2016原创,如需转载或用于商业用途需征得作者同意并注明出处


回复评论 (4)

dql,嵌入代码的时候,用编辑器的嵌入代码功能更好一些
点赞  2017-5-5 07:26
代码用专门代码插入 编辑贴子上方右边有个   <>   这点的图标,插入会更好看!
点赞  2017-5-5 09:24
引用: strong161 发表于 2017-5-5 09:24
代码用专门代码插入 编辑贴子上方右边有个      这点的图标,插入会更好看!

点赞  2017-5-5 12:14
引用: nmg 发表于 2017-5-5 07:26
dql,嵌入代码的时候,用编辑器的嵌入代码功能更好一些

点赞  2017-5-5 12:14
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复