MSP432驱动舵机串口输出角度

MSP432驱动舵机串口输出角度
备注:我用的TI官方launchpad的MSP432P401R开发板
1、舵机需要50Hz基准的PWM,占空比是0.025~0.125.如何产生PWM,当然是定时器了。查看MSP432P401R数据手册,有4个定时器。
MSP432驱动舵机串口输出角度_第1张图片
2、要算出详细的具体PWM频率,就需要知道系统的时钟,定时器的时钟。MSP432时钟来源比较复杂。具体可以看手册。(上TI官网下载)
MSP432驱动舵机串口输出角度_第2张图片
5个时钟源,这里我选择HFXTCLK外部高速时钟(48MHz)
3、定时器的时钟来源可以有4种选择
MSP432驱动舵机串口输出角度_第3张图片
这里我选择SMCLK时钟,定时器和串口都是SMCLK时钟源。
4、定时器具体配置代码
<1>、定义PWM结构并初始化

Timer_A_PWMConfig TIM0_PwmConfig =
{
		TIMER_A_CLOCKSOURCE_SMCLK,
		TIMER_A_CLOCKSOURCE_DIVIDER_4,//12MHZ / 4 = 3MHz
		60000,//3000 000 / 50 = 60000
		TIMER_A_CAPTURECOMPARE_REGISTER_1,
		TIMER_A_OUTPUTMODE_RESET_SET,
		1500//舵机初始化角度
};

<2>、定时器初始化

void TimerA0_Init(void)
{
    /* Configuring GPIO2.4 as peripheral output for PWM  */
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2, 
													GPIO_PIN4,
												    GPIO_PRIMARY_MODULE_FUNCTION);		
    /* Configuring Timer_A to have a period of approximately 500ms and
     * an initial duty cycle of 10% of that (3200 ticks)  */
    MAP_Timer_A_generatePWM(TIMER_A0_BASE, &TIM0_PwmConfig);
}

<3>、舵机角度控制

/**
 *************************************************************************
 * @brief: Servo_TurnAngle
 * @param: uch_angle -- 舵机旋转角度
 * @return: void
 * @function: 舵机旋转角度
 * @author: 
 * @version: V1.0
 * @note: 舵机需要50hz 3000000 / 60000= 50hz 60000
		 0度 0.5/20=0.025  60000*0.025= 1500
		 180度 2.5/20=0.125  60000*0.125= 7500
 *************************************************************************
**/
void Servo_TurnAngle(INT8U uch_angle)
{
	FP32 f_cycle;
	f_cycle = (7500.0f - 1500.0f) / 180.0f * uch_angle + 1500.0f;//定时器计数与角度
	TIM0_PwmConfig.dutyCycle = (INT16U)f_cycle;//新的占空比
	TIM2_PwmConfig.dutyCycle = (INT16U)f_cycle;//新的占空比
	MAP_Timer_A_generatePWM(TIMER_A0_BASE, &TIM0_PwmConfig);
}

5、串口配置代码实现
<1>、串口初始化

/**
 *************************************************************************
 * @brief: Uart0_Init
 * @param: void
 * @return: void
 * @function: 串口0初始化 波特率9600
 * @author: 
 * @version: V1.0
 * @note:http://software-dl.ti.com/msp430/msp430_public_sw/mcu/msp430/MSP430BaudRateConverter/index.html
 *************************************************************************
**/
void Uart0_Init(void)
{
	eUSCI_UART_Config uartConfig =
	{
			EUSCI_A_UART_CLOCKSOURCE_SMCLK,          // SMCLK Clock Source
			78,                                     // BRDIV = 78
			2,                                       // UCxBRF = 2
			0,                                       // UCxBRS = 0
			EUSCI_A_UART_NO_PARITY,                  // No Parity
			EUSCI_A_UART_LSB_FIRST,                  // LSB First
			EUSCI_A_UART_ONE_STOP_BIT,               // One stop bit
			EUSCI_A_UART_MODE,                       // UART mode
			EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION  // Oversampling
	};
	
    /* Selecting P1.2 and P1.3 in UART mode */
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P1,
												   GPIO_PIN2 | GPIO_PIN3, 
												   GPIO_PRIMARY_MODULE_FUNCTION);

    /* Configuring UART Module */
    MAP_UART_initModule(EUSCI_A0_BASE, &uartConfig);

    /* Enable UART module */
    MAP_UART_enableModule(EUSCI_A0_BASE);

    /* Enabling interrupts */
    MAP_UART_enableInterrupt(EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT);
    MAP_Interrupt_enableInterrupt(INT_EUSCIA0);	
	MAP_Interrupt_enableSleepOnIsrExit();
    MAP_Interrupt_enableMaster(); 
}

这里,串口时钟来源也是有4种,这里我还是选SMCLK.串口配置结构体内的参数,根据note网址计算。也可根据手册自己计算,过程比较复杂,还是用官方出的工具吧。
<2>、发送数据

/**
 *************************************************************************
 * @brief: Uart0_SendByte
 * @param: uch_byte -- 字节
 * @return: void
 * @function:
 * @author: 
 * @version: V1.0
 * @note:
 *************************************************************************
**/
void Uart0_SendByte(INT8U uch_byte)
{
	MAP_UART_transmitData(EUSCI_A0_BASE, uch_byte);
}
/**
 *************************************************************************
 * @brief: Uart0_SendDtring
 * @param: puch_buf -- 缓存指针 uin_len --数据长度
 * @return: void
 * @function: 串口发送字符串
 * @author: 
 * @version: V1.0
 * @note:
 *************************************************************************
**/
void Uart0_SendDtring(INT8U *puch_buf, INT16U uin_len)
{
	INT16U i;
	for(i = 0; i < uin_len; i++)
	{
		Uart0_SendByte(*(puch_buf + i));
	}	
}

<3>、串口接收中断服务函数

/**
 *************************************************************************
 * @brief: EUSCIA0_IRQHandler
 * @param: void
 * @return: void
 * @function: 串口中断服务函数
 * @author: 
 * @version: V1.0
 * @note:
 *************************************************************************
**/
void EUSCIA0_IRQHandler(void)
{
    uint32_t status = MAP_UART_getEnabledInterruptStatus(EUSCI_A0_BASE);

    MAP_UART_clearInterruptFlag(EUSCI_A0_BASE, status);

    if(status & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG)
    {
        MAP_UART_transmitData(EUSCI_A0_BASE, MAP_UART_receiveData(EUSCI_A0_BASE));
    }
}

接收到什么,重新发回。这里需要接收数据,增加接收缓存即可。
5、主函数代码
<1>、初始化定时器、串口

    MAP_WDT_A_holdTimer();//挂起看门狗
	SystemClockInit(HFXT);//初始化时钟到48MHz
	
	/* Enabling the FPU for floating point operation */
    MAP_FPU_enableModule();
    MAP_FPU_enableLazyStacking();//打开FPU,硬件运算浮点数
    
	CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_4);//48MHz / 4 = 12MHz
	TimerA0_Init();//定时器A0初始化
	KEY_Init();//按键初始化
	Uart0_Init();//串口0初始化 9600
	GlobalValue_Init();//全局变量初始化
	Interrupt_enableMaster();//使能全局中断

<2>、循环执行

    while (1)
    {
		Key_Scanf();//按键扫描
		if(t++ / 100)
		{
			t = 0;
			LED_Control(GREEN_LED);//绿灯
		}
		delay_us(1);//短暂延时
		sprintf((char*)buff, "舵机角度:%d\r\n", guch_ServoAngle);
		Uart0_SendDtring(buff, strlen((char*)buff));//发送数据
    }

<3>系统时钟代码


/**********************************	
	时钟:          默认时钟源        默认频率          描述
	MCLK             DCO              3MHZ          主时钟,向CPU和外设提供时钟
    HSMCLK       	 DCO              3MHZ          子系统主时钟,向外设提供时钟源
	SMCLK            DCO              3MHZ          低速系统主时钟,向外设提供时钟源
	ACLK     LFXT(或REFO没有晶振时)   32.768kHz     辅助时钟,向外设提供时钟
	BCLK     LFXT(或REFO没有晶振时)   32.768kHz     低速后配域时钟,提供LPM外设
	
********************************/
	
void SystemClockInit(u8 ClockSource)
{
 /* Halting the Watchdog */
  MAP_WDT_A_holdTimer();

	if(ClockSource==LFXT ){
///	
	        /* 配置外部低速时钟引脚*/
    MAP_GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
            GPIO_PIN0 | GPIO_PIN1, GPIO_PRIMARY_MODULE_FUNCTION);
	
    /* Setting the external clock frequency. This API is optional, but will
     * come in handy if the user ever wants to use the getMCLK/getACLK/etc
     * functions
     */
    CS_setExternalClockSourceFrequency(32768,48000000);

    /* Starting LFXT in non-bypass mode without a timeout. */
    CS_startLFXT(false);

    /* Initializing MCLK to LFXT (effectively 32khz) */ //主时钟
    MAP_CS_initClockSignal(CS_ACLK, CS_LFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);

    /* Since we are operating at 32khz, we can operating in LF mode */
   // MAP_PCM_setPowerMode(PCM_LF_MODE);
	}
	else if (ClockSource==HFXT){
		
		
		    /* 配置外部高速时钟引脚 */
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_PJ,
            GPIO_PIN3 | GPIO_PIN2, GPIO_PRIMARY_MODULE_FUNCTION);

    /* Just in case the user wants to use the getACLK, getMCLK, etc. functions,
     * let's set the clock frequency in the code. 
     */
    CS_setExternalClockSourceFrequency(32000,48000000);

    /* Starting HFXT in non-bypass mode without a timeout. Before we start
     * we have to change VCORE to 1 to support the 48MHz frequency */
    PCM_setCoreVoltageLevel(PCM_VCORE1);
    FlashCtl_setWaitState(FLASH_BANK0, 2);
    FlashCtl_setWaitState(FLASH_BANK1, 2);
    CS_startHFXT(false);//false

    /* Initializing MCLK to HFXT (effectively 48MHz) */
    MAP_CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1);
		
	}
	else  if (ClockSource==DCO){

           /*DCO时钟源配置,内部数控振荡器*/
    /* Enabling FPU for DCO Frequency calculation */
    FPU_enableModule();
    /* Setting the DCO Frequency to a non-standard 12MHz */
    CS_setDCOFrequency(CS_12MHZ);
		CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_12);//8~16MHZ
		
//	  CS_setDCOFrequency(CS_48MHZ);
//		CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_48);//8~16MHZ
		CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);
			CS_initClockSignal(CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1);//告诉子系统时钟
	}
	else {
//
        /*内部低功耗低频时钟*/
			     /*设置频率*/
    CS_setReferenceOscillatorFrequency(CS_REFO_32KHZ); 
    /* Initializing MCLK to REFO */
    MAP_CS_initClockSignal(CS_BCLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1);

    /* Since we are operating at 32khz, we can operating in LF mode */
    MAP_PCM_setPowerMode(PCM_LF_MODE);
 
	}

 
}

6、按键代码
两个按键控制舵机角度的加减
<1>、按键初始化·

/**
 *************************************************************************
 * @brief: KEY_Init
 * @param: void
 * @return: void
 * @function: 按键初始化
 * @author: 
 * @version: V1.0
 * @note:
 *************************************************************************
**/
void KEY_Init(void)
{
	MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN1);
	MAP_GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1, GPIO_PIN4);
}

<2>、按键扫描

/**
 *************************************************************************
 * @brief: Key_Scanf
 * @param: void
 * @return: void
 * @function: 按键扫描
 * @author: 
 * @version: V1.0
 * @note:
 *************************************************************************
**/
void Key_Scanf(void)
{
	if(!MAP_GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN4))//S2按下
	{
		while(!MAP_GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN4));//等待按键释放	
		if(guch_ServoAngle <= 0)
			guch_ServoAngle = 0;
		else
			guch_ServoAngle -= 5;
		Servo_TurnAngle(guch_ServoAngle);

	}
	if(!MAP_GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1))//S1按下
	{
		while(!MAP_GPIO_getInputPinValue(GPIO_PORT_P1, GPIO_PIN1));//等待按键释放
		if(guch_ServoAngle >= 180)
			guch_ServoAngle = 180;
		else
			guch_ServoAngle += 5;
		Servo_TurnAngle(guch_ServoAngle);
	}
}


你可能感兴趣的:(launchpad,msp432p401r,舵机,串口,按键)