MSP430使用库函数上手
暑假回东北参加了全国大学生智能汽车竞赛,可是学校不能住,只能回学校的实验室拿东西。于是就借了块MSP430F5529LP的开发板回来耍一耍,顺便准备一下电赛(去年也参加了,不过软件部分不是我负责的哈哈哈)。还有就是的确是自己比较懒,不是太想对照芯片手册一个一个扣寄存器,就想完全用官方出的库函数来上手。本文仅为基于LaunchPad的简单上手,还没有长期使用,一定会有一些bug隐藏其中。环境搭建编写
暑假回东北参加了全国大学生智能汽车竞赛,可是学校不能住,只能回学校的实验室拿东西。于是就借了块MSP430F5529LP的开发板回来耍一耍,顺便准备一下电赛(去年也参加了,不过软件部分不是我负责的哈哈哈)。还有就是的确是自己比较懒,不是太想对照芯片手册一个一个扣寄存器,就想完全用官方出的库函数来上手。
本文仅为基于LaunchPad的简单上手,还没有长期使用,一定会有一些bug隐藏其中。
环境搭建
编写和编译调试程序用的是ti自己出的CCS。这个应该是基于eclipse开源平台做的,和智能车隔壁双车组用英飞凌的tasking一样。
- CCS:从ti官网找的v10版本(版本号接近的话应该是差不多)
- MSP430Ware这个是官方出的软件包,里面应该是包含了官方的库函数,当然也包含了许多相关资料。安装之后可以直接新建带有库函数的430工程。
- MSP430的相关文档资料:MSP430F5529 Datasheet(芯片介绍和IO引脚等)、MSP430 User’s Guide(单片机各部分的结构框图和寄存器定义)、MSP430 DriverLib User’s Guide(官方库函数的手册,少量例程(有坑))
从ti官网下载之前可能要注册一下MyTI的账号,每次下载还要再填一个美国政府许可(大雾)。
关于库函数使用度娘能获取的内容的确较少,不过Ti官网的E2E论坛的英文区内容较多,捯饬不出问题的原因的话大家不妨去那里瞧瞧。E2E™ support forums
创建工程
和别的编译器一样找到新建Project的地方File>New>CCS Project
在Project name里面填工程名,工程目录应该是安装CCS的时候选好的,当然你也可以自己修改。
注意的是下面的Projects template and examples里面要选中MSP430DriverLib里面的Empty projects with DriverLib。
这样工程就新建好了,默认会打开里面的main.c
#include "driverlib.h"
int main(void) {
WDT_A_hold(WDT_A_BASE);//关闭看门狗
return (0);
}
时钟初始化
我手上MSP430F5529的LaunchPad有XT1和XT2两个外部时钟,XT1频率为32.768kHz,XT2频率为4MHz。
MSP430的内部时钟主要分为ACLK、SMCLK和MCLK,前两个都是供外设使用的辅助时钟,最后一个是直接供给CPU的主时钟。这三个时钟可以修改发生的时钟源,这里我配置的是ACLK为4MHz(XT2直接提供),SMCLK和MCLK都是24MHz(XT2六倍频提供),当然这个可以根据功耗和性能的需要来设置(MCLK可以超到40M,只试了一次)。
这里参考了MSP-EXP430F5529LP开发板005-PWM库函数+时钟配置
#include "driverlib.h"
//*****************************************************************************
//
//Desired Timeout for XT1 initialization
//
//*****************************************************************************
#define UCS_XT1_TIMEOUT 50000
//*****************************************************************************
//
//Desired Timeout for XT2 initialization
//
//*****************************************************************************
#define UCS_XT2_TIMEOUT 50000
//*****************************************************************************
//
//XT1 Crystal Frequency being used
//
//*****************************************************************************
#define UCS_XT1_CRYSTAL_FREQUENCY 32768
//*****************************************************************************
//
//XT2 Crystal Frequency being used
//
//*****************************************************************************
#define UCS_XT2_CRYSTAL_FREQUENCY 4000000
//*****************************************************************************
//
//Target frequency for MCLK in kHz
//
//*****************************************************************************
#define UCS_MCLK_DESIRED_FREQUENCY_IN_KHZ 24000
//*****************************************************************************
//
//MCLK/FLLRef Ratio
//
//*****************************************************************************
#define UCS_MCLK_FLLREF_RATIO 6
//*****************************************************************************
//
//Variable to store returned STATUS_SUCCESS or STATUS_FAIL
//
//*****************************************************************************
uint8_t returnValue = 0;
//*****************************************************************************
//
//Variable to store current clock values
//
//*****************************************************************************
uint32_t clockValue;
//*****************************************************************************
//
//Variable to store status of Oscillator fault flags
//
//*****************************************************************************
uint16_t status;
void ClockInit()
{
//Set VCore = 3 for 24MHz clock
PMM_setVCore(PMM_CORE_LEVEL_3);
//Initializes the XT1 and XT2 crystal frequencies being used
UCS_setExternalClockSource(UCS_XT1_CRYSTAL_FREQUENCY,UCS_XT2_CRYSTAL_FREQUENCY);
//Initialize XT1. Returns STATUS_SUCCESS if initializes successfully
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN4 + GPIO_PIN5);
returnValue = UCS_turnOnLFXT1WithTimeout(UCS_XT1_DRIVE_0,UCS_XCAP_3,UCS_XT1_TIMEOUT);
//Startup HF XT2 crystal Port select XT2
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5,GPIO_PIN2 + GPIO_PIN3);
//Initialize XT2. Returns STATUS_SUCCESS if initializes successfully
returnValue = UCS_turnOnXT2WithTimeout(UCS_XT2_DRIVE_4MHZ_8MHZ,UCS_XT2_TIMEOUT);
//Set DCO FLL reference = REFO
UCS_initClockSignal(UCS_FLLREF,UCS_XT2CLK_SELECT,UCS_CLOCK_DIVIDER_1);
//Set Ratio and Desired MCLK Frequency and initialize DCO
UCS_initFLLSettle(UCS_MCLK_DESIRED_FREQUENCY_IN_KHZ,UCS_MCLK_FLLREF_RATIO);
//Set ACLK = XT2CLK = 4MHz
UCS_initClockSignal(UCS_ACLK,UCS_XT2CLK_SELECT,UCS_CLOCK_DIVIDER_1);
//Set SMCLK = DCOCLK = 24MHz
UCS_initClockSignal(UCS_SMCLK,UCS_DCOCLK_SELECT,UCS_CLOCK_DIVIDER_1);
//Set MCLK = DCOCLK = 24MHz
UCS_initClockSignal(UCS_MCLK,UCS_DCOCLK_SELECT,UCS_CLOCK_DIVIDER_1);
}
GPIO操作
在工程的目录里面可以直接找到相关库函数.c和.h文件
直接展开gpio.h下面可以看到相关的宏定义和库函数函数名
在这里面可以看到GPIO相关的库函数,双击可以看到头文件有相关函数的使用方法,可以配置IO为输入或者输出模式,并且可以打开IO的上拉或者下拉电阻。这里要注意IO使用前要进行初始化,要使用相关IO的复用功能要提前调用带setAsPeripheral关键词的函数。
GPIO_setAsOutputPin(GPIO_PORT_P4,GPIO_PIN0+GPIO_PIN7);//Initiate GPIO
GPIO_setAsInputPin(GPIO_PORT_P1,GPIO_PIN1);
GPIO_setOutputHighOnPin(GPIO_PORT_P4,GPIO_PIN7);//Set GPIO high
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,GPIO_PIN1);
串口功能
串口初始化
这个板子单片机上是有串口直接连接到电脑上的
就是这个COM32。
在单片机上这个对应的是USCI_A1的串口模式,对应IO为P4.4和P4.5。
关于波特率的初始化,这里官方提供了表格(Uesr’s Guide的952到955页),可以简单的对常见波特率进行设置,表格按照UCOS16的值分了两个表格。
串口初始化(这里按照习惯配置波特率为115200):
void UsartInit()
{
//P3.3,4 = USCI_A0 TXD/RXD
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_ACLK;
param.clockPrescalar = 34;
param.firstModReg = 6;
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);
}
里面的clockPrescalar、firstModReg、secondModReg对应的就是UCBRx、UCBRSx和UCBRFx。
如果UCOS16 = 0,设置
param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;
如果UCOS16 = 1,设置
param.overSampling = USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION
在param结构体里面还可以进行串口终止位,奇偶校验位的设置。
串口发送
串口发送字节0x80:
USCI_A_UART_transmitData(USCI_A1_BASE,0X80);
串口发送字符串str:
void send_buf(unsigned char *ptr) //Send string.
{
while(*ptr != '\0')
{
USCI_A_UART_transmitData(USCI_A1_BASE,*ptr);
ptr++;
}
}
在CCS里面我尝试进行printf重定义没有成功,所以想实现以往串口打印的效果可以用字符串打印函数配合sprintf()函数来曲线救国:
sprintf(str,"MCLK:%ldHz\r\n",UCS_getMCLK());
send_buf(str);
sprintf(str,"SMCLK:%ldHz\r\n",UCS_getSMCLK());
send_buf(str);
sprintf(str,"ACLK:%ldHz\r\n",UCS_getACLK());
send_buf(str);
例为获取MCLK、SMCLK和ACLK并通过串口发送到串口助手。
当然如果想让sprinf()里面能够打印float或者long型数据时,还要在Project>Properties>Build>MSP430 Complier>Edit Flags…里面将printf_support=minimal改为printf_support=full才能使用完整的printf功能。
串口中断
receivedData为接收的数据
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=USCI_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(USCI_A1_VECTOR)))
#endif
void USCI_A1_ISR (void)
{
switch (__even_in_range(UCA1IV,4))
{
case USCI_UCRXIFG:
receivedData = USCI_A_UART_receiveData(USCI_A1_BASE);
USCI_A_UART_transmitData(USCI_A1_BASE,receivedData);
break;
default:
break;
}
}
定时器A
MSP430F5529片上有定时器TA0、TA1、TA2、TB0,其中定时器A的使用方法大致相同,其中TA0在LaunchPad引出IO较多,故简易将TA0用作PWM发生器,TA1用作程序10ms中断发生器,TA2用作PWM脉宽捕获。
PWM发生
初始化定时器和GPIO,这里PWM频率 = SMCLK / timerPeriod = 20kHz
void timerA0PWMInit()z
{
GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1, GPIO_PIN2+GPIO_PIN3);//初始化GPIO
Timer_A_outputPWMParam param;
param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//选择时钟源
param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;//时钟源不分频
param.timerPeriod = 1200;//定时器装载值
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//初始化捕获比较寄存器1,对应通道TA0.1
param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//选择输出模式
param.dutyCycle = 0;//
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;//初始化捕获比较寄存器2,对应通道TA0.2
Timer_A_outputPWM(TIMER_A0_BASE,¶m);
}
由于对捕获比较寄存器1和2的默认重装值为0,输出PWM占空比为0%,故要后期设置比较寄存器的值,若比较寄存器设置为1200即等于timerPeriod时PWM占空比为100%。
设置捕获比较寄存器:
Timer_A_setCompareValue(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1,
100);//Reload PWM output for P1.2
Timer_A_setCompareValue(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2,
200);//Reload PWM output for P1.3
定时器中断
定时器A1初始化:
void TimerA1Init()
{
Timer_A_initUpModeParam param = {0};
param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;
param.timerPeriod = 24000;
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);
}
这里定时器输入时钟为SMCLK=24MHz,10倍分频后为2400000Hz,中断频率 = SMCLK / 10 /timerPeriod = 100Hz,中断周期10ms。
中断服务函数:
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER1_A0_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(TIMER1_A0_VECTOR)))
#endif
void TIMER1_A0_ISR (void)
{
GPIO_toggleOutputOnPin(GPIO_PORT_P4,GPIO_PIN7);
}
输入捕获
输入捕获是我比较纳闷的地方,我使用的是定时器A2的上升下降沿捕获,可是我并没有找到获取当前是上升沿中断还是下降沿中断状态的库函数或者是宏定义入口,故在进入中断后对输入捕获引脚进行了电平检测(天呐这法子太土了)。
不过这个输入捕获代码在捕获单一方波输入时没有问题,可是在捕获同一个上升沿的方波时(因为两个输入同时触发中断),会出现输入通道2捕获的值不正常的问题。
定时器初始化:
void TimerA2CaptureInit()
{
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);
}
中断服务函数:
在这里插入代码片#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=TIMER2_A1_VECTOR
__interrupt
#elif defined(__GNUC__)
__attribute__((interrupt(TIMER2_A1_VECTOR)))
#endif
void TIMER2_A1_ISR (void)
{
static uint8_t overflow1 = 0,overflow2 = 0;
switch(TA2IV)
{
case TA2IV_TACCR1:
if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN4))
{
pwm_start1 = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
}
else
{
pwm_end1 = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
if(!overflow1)
pwm_wide1 = pwm_end1 - pwm_start1;
else
{
pwm_wide1 = (long)(65536*overflow1 - pwm_start1 + pwm_end1);
overflow1 = 0;
}
}
Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1);
break;
case TA2IV_TACCR2:
if(GPIO_getInputPinValue(GPIO_PORT_P2,GPIO_PIN5))
{
pwm_start2 = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
}
else
{
pwm_end2 = Timer_A_getCaptureCompareCount(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
if(!overflow2)
pwm_wide2 = pwm_end2 - pwm_start2;
else
{
pwm_wide2 = (long)(65536*overflow2 - pwm_start2 + pwm_end2);
overflow2 = 0;
}
}
Timer_A_clearCaptureCompareInterrupt(TIMER_A2_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2);
break;
case TA2IV_TAIFG:
overflow2++;
overflow2++;
Timer_A_clearTimerInterrupt(TIMER_A2_BASE);
break;
}
}
通过TA2IV可以区分该中断是来自哪个IO的捕获中断,其中pwm_wide1和pwm_wide2为捕获到的方波脉宽数值。
对TIMER2_A1_VECTOR右键Open Declaration可以看到代表中断向量的含义:
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER2_A1_VECTOR ".int43"/* 0xFFD6 Timer2_A5 CC1-4, TA */
#else
#define TIMER2_A1_VECTOR (43 * 1u)/* 0xFFD6 Timer2_A5 CC1-4, TA */
#endif
#ifdef __ASM_HEADER__ /* Begin #defines for assembler */
#define TIMER2_A0_VECTOR ".int44" /* 0xFFD8 Timer2_A5 CC0 */
#else
#define TIMER2_A0_VECTOR (44 * 1u) /* 0xFFD8 Timer2_A5 CC0 */
#endif
这里是定时器A2的中断向量,其中TIMER2_A0_VECTOR指向来自通道0的中断(定时器中断也来自这里),TIMER2_A1_VECTOR指向来自通道1-4的中断。不得不说,这里这里命名真是足够混乱。
ADC12单次多通道读取
初始化:
void ADC12AInit()
{
GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6, GPIO_PIN2 + GPIO_PIN3);
// 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_6);
//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_ENDOFSEQUENCE;
ADC12_A_configureMemory(ADC12_A_BASE ,¶m);
}
ADC初始化时,需要将最后一个通道的endOfSequence设置为ADC12_A_ENDOFSEQUENCE,其他通道设置为ADC12_A_NOTENDOFSEQUENCE。
ADC单次调用读取:
void ADCRead()
{
int i;
for(i=0;i<4;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_2,
ADC12_A_SEQOFCHANNELS);
// Wait for the Interrupt Flag to assert
while( !(ADC12_A_getInterruptStatus(ADC12_A_BASE,ADC12IFG0)) );
// Clear the Interrupt Flag and start another conversion
ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12IFG0);
ADCValue[0] += 0.1*ADC12MEM2;
ADCValue[1] += 0.1*ADC12MEM3;
}
}
这里的读取函数连续读取了10次并进行了简单的均值滤波。
转换结果储存在ADCValue[]内。
主函数
最重要的还是要在初始化之后加上__enable_interrupt(),不然所有的中断都不会进去。
int main(void) {
WDT_A_hold(WDT_A_BASE);
ClockInit();
UsartInit();
timerA0PWMInit();//Initiate timer A0 PWM output
Timer_A_setCompareValue(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_1,
100);//Reload PWM output for P1.2
Timer_A_setCompareValue(TIMER_A0_BASE,TIMER_A_CAPTURECOMPARE_REGISTER_2,
200);//Reload PWM output for P1.3
TimerA1Init();//Initiate timer A1 for interrupt every 1ms
TimerA2CaptureInit();
ADC12AInit();
__enable_interrupt();
OLED_Init(); //Initiate OLED
OLED_Clear();
GPIO_setAsOutputPin(GPIO_PORT_P4,GPIO_PIN0+GPIO_PIN7);//Initiate GPIO
GPIO_setAsInputPin(GPIO_PORT_P1,GPIO_PIN1);
GPIO_setOutputHighOnPin(GPIO_PORT_P4,GPIO_PIN7);//Set GPIO high
GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P1,GPIO_PIN1);
char str[100];
OLED_Clear();
sprintf(str,"MCLK:%ldHz\r\n",UCS_getMCLK());
send_buf(str);
sprintf(str,"SMCLK:%ldHz\r\n",UCS_getSMCLK());
send_buf(str);
sprintf(str,"ACLK:%ldHz\r\n",UCS_getACLK());
send_buf(str);
while(1)
{
ADCRead();
}
return (0);
}
更多推荐
所有评论(0)