msp430f5529库函数总结
说好的做完电设发源码,结果托更的时间有点长看,作为补偿这边博客写的详尽一些,希望各位能够看完就会用。
吐槽一下,TI官方公布的库函数只有几个示例,我在比赛前自己移植了一边所有的基础功能,比如uart,iic,spi,pwm,定时器等,iic和spi最为难调,也不知道底层写的怎么样,只能通过示波器看现象,按照经验调。
源码链接:https://download.csdn.net/download/YOUNGAAAAA/85007021
先介绍一下msp430f5529:
板载一个32.768K的RTC时钟XTAL1和一个4MHz 的时钟
GPIO:
P1、P2支持中断,分别公用一个中断向量。
Pwm引脚:
中断:
定时器:
时钟
这一款芯片主打低功耗,如果作为电赛人推荐用432,功能多,主频还高。缺点显而易见就是主频低,如果全低功耗的情况下系统时钟只有1Mhz,你没看错,这跑个锤子。
所以第一步先要将主频拉高,再往前一步说就是要走出低功耗的范围,将内核电压拉高。
直接上代码:
void clock_init(unsigned char Fre)
{
P5SEL |= BIT2|BIT3|BIT4|BIT5;//开启外部两个时钟
UCSCTL6 |= XCAP_3|XT1OFF; // XT1 相关 配置
UCSCTL6 |= XT2DRIVE_0 |XT2OFF; // XT2 相关 配置
//以下是提升核心电压部分的代码
PMMCTL0_H = 0xA5; //开PMM电源管理
SVSMLCTL |= SVSMLRRL_1 + SVMLE; //配置SVML电压
PMMCTL0 = PMMPW + PMMCOREV_3; //配置内核电压
while((PMMIFG & SVSMLDLYIFG ) == 0); //等待设置完成
PMMIFG &= ~(SVMLVLRIFG + SVMLIFG + SVSMLDLYIFG);
if((PMMIFG & SVMLIFG) == 1) //判断内核电压是否上升到VSVML
while((PMMIFG & SVMLVLRIFG) == 0); //如果没有等待
SVSMLCTL &= ~SVMLE; //关掉SVML模块
PMMCTL0_H = 0X00;
__bis_SR_register(SCG0); //该语法为固定格式,意为将括号内的变量置位,SCG0与系统工作模式有关,此时 MCLK 暂停工作
UCSCTL0 = 0; //先清零,FLL 运行时,该寄存器系统会自动配置,不用管
UCSCTL6 = (UCSCTL6&(~(XT2OFF|XT1OFF))|XCAP_3|XT2DRIVE_0);
UCSCTL3 = (5<<4)|(2<<0); // 选择 XTAL2 的时钟信号作为参考信号 并且分频到1MHz
if(Fre < 5)
UCSCTL1 = DCORSEL_2;
else if(Fre<15)
UCSCTL1 = DCORSEL_4;
else
UCSCTL1 = DCORSEL_7;
UCSCTL2 = (Fre-1);
__bic_SR_register(SCG0);
__delay_cycles(782000);
while (SFRIFG1 & OFIFG) { // Check OFIFG fault flag
UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG); // Clear OSC flaut Flags
SFRIFG1 &= ~OFIFG; // Clear OFIFG fault flag
}
UCSCTL4 = UCSCTL4&(~(SELS_7|SELM_7))|SELS_3|SELM_3;
}
只需要再初始化的时候将这个函数加上即可,代替原有的clock_init(frequency Mhz);
比如这里超频到40Mhz,实测不要超过44Mhz,不然系统运行很不稳定。
定时器
TIMB(1ms周期定时器,用作控制中断), TIMA0(4路pwm输出 20khz 用于电驱),TIMA1(50hz pwm输出,舵机控制),TIMA2(输入捕获)四个定时器都用上了
void TimerBInit(void)//40M/10/4000 = 1ms
{
Timer_B_initUpModeParam paramB = {0};
paramB.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
paramB.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_10;
paramB.timerPeriod = 4000;
paramB.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE;
paramB.captureCompareInterruptEnable_CCR0_CCIE = TIMER_B_CCIE_CCR0_INTERRUPT_ENABLE;
paramB.timerClear = TIMER_B_DO_CLEAR;
paramB.startTimer = true;
Timer_B_initUpMode(TIMER_B0_BASE,¶mB);
Timer_B_startCounter( TIMER_B0_BASE,TIMER_B_UP_MODE);
}
void timerA0PWMInit(void) //40Mhz/1/2000=20khz
{
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,GPIO_PIN2+GPIO_PIN3+GPIO_PIN4+GPIO_PIN5);//初始化GPIO
Timer_A_outputPWMParam param;
param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//选择时钟源
param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;//时钟源不分频
param.timerPeriod = 2000;//定时器装载值
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//初始化捕获比较寄存器1,对应通道TA0.1
param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//选择输出模式
param.dutyCycle = 1000;//
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;//初始化捕获比较寄存器2,对应通道TA0.2
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_3;//初始化捕获比较寄存器2,对应通道TA0.3
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_4;//初始化捕获比较寄存器2,对应通道TA0.4
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
}
void timerA1PWMInit(void) //40M/40/20000=50hz
{
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,GPIO_PIN0);
Timer_A_outputPWMParam param1;
param1.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//选择时钟源
param1.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_40;//时钟源不分频
param1.timerPeriod = 20000;//定时器装载值
param1.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//初始化捕获比较寄存器1,对应通道TA0.1
param1.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//选择输出模式
param1.dutyCycle = 0;//
Timer_A_outputPWM(TIMER_A1_BASE,¶m1);
// Timer_A_initUpModeParam param = {0};
// param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
// param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;
// param.timerPeriod = 4000;
// param.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
// param.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
// param.timerClear = TIMER_A_DO_CLEAR;
// param.startTimer = true;
// Timer_A_initUpMode(TIMER_A1_BASE,¶m);
// Timer_A_startCounter( TIMER_A1_BASE,TIMER_A_UP_MODE);
}
void TimerA2CaptureInit(void) //40/1
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN4 + GPIO_PIN5);
Timer_A_initContinuousModeParam param0 = {0};
param0.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
param0.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
param0.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
param0.timerClear = TIMER_A_DO_CLEAR;
param0.startTimer = true;
Timer_A_initContinuousMode(TIMER_A2_BASE,¶m0);
Timer_A_initCaptureModeParam param1 = {0};
param1.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
param1.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
param1.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
param1.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
param1.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
param1.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
Timer_A_initCaptureMode(TIMER_A2_BASE,¶m1);
param1.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;//Two capture intputs PWM cannot start or end in the same time.
param1.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
Timer_A_initCaptureMode(TIMER_A2_BASE,¶m1);
}
uart
两个串口,应该够用了,接收中断是必须开的,不然在哪放接收处理函数。
void Usart1Init(void)
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);
//Baudrate = 115200, clock freq = 4MHz
//UCBRx = 34, UCBRFx = 6, UCBRSx = 0, UCOS16 = 0
USCI_A_UART_initParam param = {0};
param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
param.clockPrescalar = 347;
param.firstModReg = 2;
param.secondModReg = 0;
param.parity = USCI_A_UART_NO_PARITY;
param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
param.uartMode = USCI_A_UART_MODE;
param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;
if (STATUS_FAIL == USCI_A_UART_init(USCI_A1_BASE, ¶m))
{
return;
}
//Enable UART module for operation
USCI_A_UART_enable(USCI_A1_BASE);
//Enable Receive Interrupt
USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}
void Usart0Init(void)
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,GPIO_PIN4 + GPIO_PIN3);
USCI_A_UART_initParam param = {0};
param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
param.clockPrescalar = 347;
param.firstModReg = 2;
param.secondModReg = 0;
param.parity = USCI_A_UART_NO_PARITY;
param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
param.uartMode = USCI_A_UART_MODE;
param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;
if (STATUS_FAIL == USCI_A_UART_init(USCI_A0_BASE, ¶m)){
return;
}
//Enable UART module for operation
USCI_A_UART_enable(USCI_A0_BASE);
//Enable Receive Interrupt
USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}
uart必须支持printf,配置不难
/*printf redefine*/
int fputc(int ch,FILE *f)
{
UCA1TXBUF = ch&0xff;
while(!(UCA1IFG & UCTXIFG));//等待发送完成
return ch;
}
int fputs(const char *_ptr, register FILE *_fp)
{
unsigned int i, len;
len = strlen(_ptr);
for(i=0 ; i<len ; i++){
UCA1TXBUF = _ptr[i]&0xff;
while(!(UCA1IFG & UCTXIFG));//等待发送完成
}
return len;
}
void send0(unsigned char *ptr) //Send string.
{
while(*ptr != '\0')
{
USCI_A_UART_transmitData(USCI_A0_BASE,*ptr);
ptr++;
}
}
ADC
adc初始化(6路)和读取函数(平均滤波);
void ADC12AInit(void) //40Mhz / 8 =5Mhz
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6, GPIO_PIN1+GPIO_PIN2 + GPIO_PIN3 + GPIO_PIN4 + GPIO_PIN5 + GPIO_PIN6);
// Initialize ADC12 with ADC12’s built-in oscillator
ADC12_A_init (ADC12_A_BASE,ADC12_A_SAMPLEHOLDSOURCE_SC,ADC12_A_CLOCKSOURCE_SMCLK,ADC12_A_CLOCKDIVIDER_3);
//Switch ON ADC12
ADC12_A_enable(ADC12_A_BASE);
// Setup sampling timer to sample-and-hold for 16 clock cycles
ADC12_A_setupSamplingTimer (ADC12_A_BASE,ADC12_A_CYCLEHOLD_64_CYCLES,ADC12_A_CYCLEHOLD_4_CYCLES,ADC12_A_MULTIPLESAMPLESENABLE);
// Configure the Input to the Memory Buffer with the specified Reference Voltages
ADC12_A_configureMemoryParam param = {0};
param.memoryBufferControlIndex = ADC12_A_MEMORY_2;
param.inputSourceSelect = ADC12_A_INPUT_A2;
param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
param.memoryBufferControlIndex = ADC12_A_MEMORY_3;
param.inputSourceSelect = ADC12_A_INPUT_A3;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
param.memoryBufferControlIndex = ADC12_A_MEMORY_1;
param.inputSourceSelect = ADC12_A_INPUT_A1;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
param.memoryBufferControlIndex = ADC12_A_MEMORY_4;
param.inputSourceSelect = ADC12_A_INPUT_A4;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
param.memoryBufferControlIndex = ADC12_A_MEMORY_5;
param.inputSourceSelect = ADC12_A_INPUT_A5;
param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
param.memoryBufferControlIndex = ADC12_A_MEMORY_6;
param.inputSourceSelect = ADC12_A_INPUT_A6;
param.endOfSequence = ADC12_A_ENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
}
void ADCRead(void)
{
int i;
for(i=0;i<7;i++) ADCValue[i]=0;
for(i=0;i<10;i++)
{
// Start a single conversion, no repeating or sequences.
ADC12_A_startConversion (ADC12_A_BASE,ADC12_A_MEMORY_1,ADC12_A_SEQOFCHANNELS);
// Wait for the Interrupt Flag to assert
while( !(ADC12_A_getInterruptStatus(ADC12_A_BASE,ADC12_A_IFG1)) );
// Clear the Interrupt Flag and start another conversion
ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12_A_IFG1);
// ADCValue[0] += 0.1*ADC12MEM0;
ADCValue[0] += 0.1*ADC12MEM1;
ADCValue[1] += 0.1*ADC12MEM2;
ADCValue[2] += 0.1*ADC12MEM3;
ADCValue[3] += 0.1*ADC12MEM4;
ADCValue[4] += 0.1*ADC12MEM5;
ADCValue[5] += 0.1*ADC12MEM6;
for(i=0;i<9;i++)
{
ADCVfinal[i] = ADCValue[i]*3.3/4096;
ADCVfinal[i] = ADCVfinal[i]*10;
}
}
}
可能有人会发现为啥没有ADC12_A_MEMORY_0,问就是有bug调不出来。未知问题就这个用不了。
iic
iic实测是有点bug的,谨慎使用,本来是用它来驱动oled屏幕,用是能用,出奇的慢,其他设备iic通过没试过。
void iic_init()
{
GPIO_setAsOutputPin(GPIO_PORT_P3,GPIO_PIN1);
uint8_t i=0;
// 输出9个时钟以恢复I2C总线状态
for( i= 0; i <9 ; i++)
{
GPIO_setOutputHighOnPin(GPIO_PORT_P3,GPIO_PIN1);
__delay_cycles(8000);
GPIO_setOutputLowOnPin(GPIO_PORT_P3,GPIO_PIN1);
__delay_cycles(8000);
}
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_P3,
GPIO_PIN1 + GPIO_PIN0
);
//Initialize transmit data packet
transmitData = 0x01;
//Initialize Master
USCI_B_I2C_initMasterParam param = {0};
param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;
param.i2cClk = UCS_getSMCLK();
param.dataRate = USCI_B_I2C_SET_DATA_RATE_100KBPS;
USCI_B_I2C_initMaster(USCI_B0_BASE, ¶m);
//Specify slave address
USCI_B_I2C_setSlaveAddress(USCI_B0_BASE,
SLAVE_ADDRESS
);
//Set in transmit mode
USCI_B_I2C_setMode(USCI_B0_BASE,
USCI_B_I2C_TRANSMIT_MODE
);
//Enable I2C Module to start operations
USCI_B_I2C_enable(USCI_B0_BASE);
}
spi
spi没啥问题,这样配置也差不多了。用于ICM20602,所以初始化了一些其他io。
void spi_init(void)
{
//Set P1.1 for slave reset
GPIO_setAsOutputPin(GPIO_PORT_P7,GPIO_PIN4);
//P3.5,4,0 option select
GPIO_setAsPeripheralModuleFunctionInputPin(
GPIO_PORT_P3,
GPIO_PIN1 + GPIO_PIN2 + GPIO_PIN0
);
//Initialize Master
USCI_B_SPI_initMasterParam param = {0};
param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;
param.clockSourceFrequency = UCS_getSMCLK();
param.desiredSpiClock = SPICLK;
param.msbFirst = USCI_B_SPI_MSB_FIRST;
param.clockPhase = USCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
returnValue = USCI_B_SPI_initMaster(USCI_B0_BASE, ¶m);
if (STATUS_FAIL == returnValue){
return;
}
//Enable SPI module
USCI_B_SPI_enable(USCI_B0_BASE);
//Enable Receive interrupt
USCI_B_SPI_clearInterrupt(USCI_B0_BASE, USCI_B_SPI_RECEIVE_INTERRUPT);
USCI_B_SPI_enableInterrupt(USCI_B0_BASE, USCI_B_SPI_RECEIVE_INTERRUPT);
//LED On
GPIO_setOutputHighOnPin(GPIO_PORT_P1,GPIO_PIN0);
GPIO_setOutputHighOnPin(GPIO_PORT_P7,GPIO_PIN4);
//Wait for slave to initialize
__delay_cycles(100);
//USCI_A0 TX buffer ready?
while (!USCI_B_SPI_getInterruptStatus(USCI_B0_BASE,
USCI_B_SPI_TRANSMIT_INTERRUPT)) ;
}
外部中断
这段代码最后那一部分是自己写的软件编码器设定的参数,和控制代码放在一个定时中断就可以用,有兴趣的下载源码看看,写了几天,效果和输入捕获的没差别,还能省一个定时器。
void EXIT_init(void)
{
//Enable internal resistance as pull-down resistance and interrupt enabled
GPIO_setAsInputPinWithPullDownResistor(GPIO_PORT_P2,GPIO_PIN3);
GPIO_enableInterrupt(GPIO_PORT_P2,GPIO_PIN3);
GPIO_setAsInputPinWithPullDownResistor(GPIO_PORT_P2,GPIO_PIN6);
GPIO_enableInterrupt(GPIO_PORT_P2,GPIO_PIN6);
GPIO_selectInterruptEdge(GPIO_PORT_P2,GPIO_PIN3,GPIO_LOW_TO_HIGH_TRANSITION);
GPIO_selectInterruptEdge(GPIO_PORT_P2,GPIO_PIN6,GPIO_LOW_TO_HIGH_TRANSITION);
// IFG cleared
GPIO_clearInterrupt(GPIO_PORT_P2,GPIO_PIN3);
GPIO_clearInterrupt(GPIO_PORT_P2,GPIO_PIN6);
//dir config
GPIO_setAsInputPin(GPIO_PORT_P4,GPIO_PIN3);
GPIO_setAsInputPin(GPIO_PORT_P8,GPIO_PIN1);
encoder1.M=0;
encoder1.M_speed=0;
encoder1.T = 0;
encoder1.T_count=0;
encoder1.T_sum=0;
encoder1.T_time=0;
encoder1.index = 0;
encoder1.EXTI_FLAG = 0;
encoder2.M=0;
encoder2.M_speed=0;
encoder2.T = 0;
encoder2.T_count=0;
encoder2.T_sum=0;
encoder2.T_time=0;
encoder2.index = 0;
encoder2.EXTI_FLAG = 0;
}
中断配置再isr.c,定时器中断,外部中断等,硬件编码器,软件编码器都在。
有需求自己拿哈,望各位电赛人取得好成绩。
私戳的话不一定能及时看到,比较佛系。