2025年msp430单片机应用实例(msp430单片机原理与应用实例详解)

msp430单片机应用实例(msp430单片机原理与应用实例详解)MSP430F5529 的 launchpad 是 TI 送的比较多的一款开发套件 至少我们实验室就是人手一块 很多人都嫌他慢 确实相比较于 STM32F103 72MHz 和 STM32F407 168MHz 的速度而言 nbsp 默认状态下主频只有 1MHz 的 MSP430F5529 就是个弟弟 而且处理位宽也是只有 16 位 还不支持位带操作 nbsp 但是就超低功耗这一点就足以让他在单片机界立足 废话少说 来正题 这次跟大家分享的是标题所说的 nbsp



MSP430F5529的launchpad是 TI送的比较多的一款开发套件,至少我们实验室就是人手一块,很多人都嫌他慢,确实相比较于STM32F103(72MHz) 和STM32F407(168MHz)的速度而言 默认状态下主频只有1MHz的 MSP430F5529就是个弟弟,而且处理位宽也是只有16位,,, 还不支持位带操作 ,但是就超低功耗这一点就足以让他在单片机界立足 ,废话少说,来正题。


这次跟大家分享的是标题所说的 MSP430F5529的升频方案。


要升频,首先我们得能‘看见’系统的频率,TI的工程师们充分考虑到了这个问题,他们有得引脚可以直接输出时钟信号!!!


在芯片datesheet中 的Terminal Functions 里有如下说明

所以我们可以通过设置相应的 状态来输出时钟信号, IO配置成输出+ 功能复用

以上 我们实现了 时钟的输出 ,通过测量上述的三个IO ,我们可以得到系统的不同时钟。 接下来就是对时钟的配置


主要就是配置UCS(Unified Clock System (UCS))的一些寄存器。 不过 在这之前 我们要先把核心电压升上去,430为了省电默认状态下核心电压默认设置为1.8V来节省功耗。 在用户手册的2.2.4节提到了升核心电压的方法


开启PMM管理的操作 第一步是解锁 向PMMCTL0 寄存器高8位写入 0xA5 然后设置核心电压等级是三级(官方手册有提到频率和核心电压的关系)

这里要提一下 ,我调用官方的 SetVcore()函数并不能实现效果不知道为什么 。。。。有知道的大佬还望不吝赐教


到这里 我们的核心的电压已经设置完成了,接下来就是时钟的配置了,其他大佬们也提到了很多,我这里就是按照一位大佬的做法实现的,不是原创! 只是对前人思路的理解.. 代码如下

第一步是 令 SR寄存器里面的 SCG0=1, 我猜测这里的目的应该是

我猜测这一步的作用应该是关闭锁相环,同时 关闭了这个时钟以后系统时钟应该会自动切换到备用时钟。 关闭了这个以后就可以开始对时钟进行设置了。 UCSCTL0 是直接关闭了DCO的输出

查看芯片的技术手册发现0x60(DCORSEL_6)确实是最优解! 同时0x50(DCORSEL_5)和 0x70(DCORSEL_7)也是可以选择的!


接着理解下一步 UCSCTL2 = FLLD_1 | 380;

接下来我们看一下这些bit到底是设置了什么

通过 这些默认的设置

初步判断时钟是从XT1CLK 来的

XT1 也就是我们先前使能的 外部晶振 P5.4 P5.5

然后我们打开launchpad的手册 在clock相关的部分也确实证实了 XTL1 是32.768KHz的晶振

XT1 的 bypass是 默认置0的 完整的时钟信号走向应该是这样的

实现效果是这样的  

这里的示波器选用的是 Loto 的虚拟示波器 OSC802


示波器的引脚接到了 P2.2脚 我也是最近才开始捡起 430的 ,很多东西都不是很熟,出错在所难免,请各位大佬们不吝赐教!

*****************************************软件延时************************************/
# define CPU_F ((double)8000000)
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
/**************************************************************************************/
#define CPU_F((double)8000000)中的8000000表示的是你系统的时钟,该值要随你试验系统的改变而改变。本例中8000000为MCLK=8MHz的意思。

以下例程是分别产生微秒级和毫秒级延时的示范,如果要实现不同的延时只要改变程序中的实参就可以了。调用此程序时实参必是数字,而不能使用变量作为实参。
       理论上各个延时函数可以达到如下精度:
       delay_us(1);    //延时1us
       delay_ms(1);    //延时1ms
       delay_us(4.2); //延时4.2us
       delay_ms(4.2); //延时4.2ms

上诉例程我用MSP430F448平台测试,现将所用程序及实测结果发布如下,供各位参考:
1MHZ主频下软件定时情况:
程序:


#include
/*****************************************软件延时************************************/
#define CPU_F ((double)1000000)
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))  
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
/**************************************************************************************/
//1000000是CPU的主频,即MCLK,需要随系统的改变而改变
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;                 
P1DIR = 0x22;                              
P1SEL = 0x22;
P2DIR=0X01;                                
for(;;)
{
    delay_us(1);   
    P2OUT^=0X01;
}                              
}


结果:
//delay_us(1): 实际延时时间为6.8us
//delay_us(10); 实际延时时间为15.6us
//delay_us(20); 实际延时时间为24.8us
//delay_us(90); 实际延时时间为92us
//delay_us(100); 实际延时时间为100us
//delay_us(900); 实际延时时间为880us
//delay_us(1000);实际延时时间为0.96ms
//delay_ms(1);   实际延时时间为0.96ms
//delay_ms(10); 实际延时时间为9.6ms
//delay_ms(100); 实际延时时间为96ms
//delay_ms(500); 实际延时时间为480ms
//delay_ms(1000); 实际延时时间为950ms
//delay_ms(10000); 实际延时时间为10s

2MHZ主频如下:
程序
#include
/*****************************************软件延时************************************/
#define CPU_F ((double)2000000)
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))  
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
/**************************************************************************************/
//2000000是CPU的主频,即MCLK,需要随系统的改变而改变
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;                  
FLL_CTL0 |= XCAP18PF;                      
SCFI0 |= FN_2;                             
SCFQCTL = 60;          
P1DIR = 0x22;                             
P1SEL = 0x22;
P2DIR=0X01;                                
for(;;)
{
    delay_ms(1000);   
    P2OUT^=0X01;
}                              
}
结果:
//delay_us(1): 实际延时时间为4us
//delay_us(10); 实际延时时间为13.2us
//delay_us(20); 实际延时时间为23.2us
//delay_us(90); 实际延时时间为92us
//delay_us(100); 实际延时时间为104us
//delay_us(900); 实际延时时间为900us
//delay_us(1000);实际延时时间为1.04ms
//delay_ms(1);   实际延时时间为1.04ms
//delay_ms(10); 实际延时时间为10ms
//delay_ms(100); 实际延时时间为100ms
//delay_ms(500); 实际延时时间为500ms
//delay_ms(1000); 实际延时时间为1000ms
//delay_ms(10000); 实际延时时间为10s

8MHZ主频:
程序:
#include
/*****************************************软件延时************************************/
#define CPU_F ((double)8000000)
#define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))  
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
/**************************************************************************************/
//8000000是CPU的主频,即MCLK,需要随系统的改变而改变
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
FLL_CTL0 |= DCOPLUS+XCAP18PF;             // Set load capacitance for xtal
SCFI0 |= FN_4;                            // x2 DCO, 4MHz nominal DCO
SCFQCTL = 121;                            // (121+1) x 32768x 2= 8Mhz    
P1DIR = 0x22;                             // P1.1 & P1.5 to output direction
P1SEL = 0x22;
P2DIR=0X01;                               // P1.1 & P1.5 to output MCLK & ACLK
for(;;)
{
    delay_ms(1000);   
    P2OUT^=0X01;
}                              
}
结果:
//delay_us(1): 实际延时时间为1.75us
//delay_us(10); 实际延时时间为10.80us
//delay_us(20); 实际延时时间为20.8us
//delay_us(90); 实际延时时间为90.5us
//delay_us(100); 实际延时时间为100us
//delay_us(900); 实际延时时间为900us
//delay_us(1000);实际延时时间为1ms
//delay_ms(1);   实际延时时间为1ms
//delay_ms(10); 实际延时时间为10ms
//delay_ms(100); 实际延时时间为100ms
//delay_ms(500); 实际延时时间为500ms
//delay_ms(1000); 实际延时时间为1s
//delay_ms(10000); 实际延时时间为10s


上述测试说明:
程式用于20us以下的延时,误差会比较大,主频越高误差越小;
大于20us小于1000ms的延时,定时时间几乎没有什么误差。

在系统实时性要求比较高的情况下,10ms以上的延时采用软件来实现不是很好的选择,建议采用硬件方式。对于us级的延时,本文提供的程式非常有实用价值。

环境:windows xp,ccs5.4


使用Ti官方的uart串口程序


#include



int main(void)

{

WDTCTL = WDTPW + WDTHOLD; // Stop WDT

if (CALBC1_1MHZ==0xFF) // If calibration constant erased

{

while(1); // do not load, trap CPU!!

}

DCOCTL = 0; // Select lowest DCOx and MODx settings

BCSCTL1 = CALBC1_1MHZ; // Set DCO

DCOCTL = CALDCO_1MHZ;

P3SEL = 0x30; // P3.4,5 = USCI_A0 TXD/RXD

UCA0CTL1 |= UCSSEL_2; // SMCLK

UCA0BR0 = 52; // 1MHz 19200我设置了一个8M赫兹的一个值,所以这里需要查看用户定义中的一张表格来确定

UCA0BR1 = 0; // 1MHz 19200这个同上

UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1设置的一个分频系数,不太清楚怎么配置,好像换成8M以后还可以用的

UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**

IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt


__bis_SR_register(LPM0_bits + GIE); // Enter LPM0, interrupts enabled

}


//串口中断,有数据读取到时发生一个中断。。。。实例这边将受到的数据直接发送出去。当然可以可以做一个缓存,把收到的数据保存,然后出来

// Echo back RXed character, confirm TX buffer is ready first

#pragma vector=USCIAB0RX_VECTOR

__interrupt void USCI0RX_ISR(void)

{

while (!(IFG2 & UCA0TXIFG)); // USCI_A0 TX buffer ready?

UCA0TXBUF = UCA0RXBUF; // TX -> RXed character

}


遇到的一个问题:


使用串口助手调试的时候,发现有数据,但是数据完全错误。后来单独盘查,寄存器配置,串口线,与串口调试软件,均没有发现问题。后来把msp430烧写程序的烧录器拔掉好像就好了,可能是端口冲突!


今天学了一下msp430 ad转换,编程ad单通道单次转换。


首先顺一下思路:


adc12 :单通道单次转换流程,开了adc12on 后,shs (选择输入信号源)= 0,ENC上跳,adc12sc 上跳, 开始采样,经过采样保持时间,转换成功,值放在adc12MEMx中。发生中断,adcifg置位,读取后adc12mem 后,自动复位。




相关寄存器:


ADC12CTL0 : SHT0_2 + ADC12ON


设置采样保持时间,打开内核




ADC12CTL1 : SHS(DEFAULT) ,SHP(1) 定时器,




ADC12CTL0:ENC,ADC12SC 置位




while(1)


{


ADC12SC 置位;


diaplay(转换数据);


}




interrupt()


{


read ADC12MEM0;


}






参考程序:


#include

#define uchar unsigned char

#define uint unsigned int

uchar table[16] ={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,

0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

uchar position[8] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

uchar count=1,count1=0,i,j;

uchar temp,result[4],index ;

void show(uchar pos,uchar num)

{

P4OUT = 0x00; // tobe all turn off

P6OUT |= 0x40; // DUAN open

P4OUT = table[num]; //DUAN NUM

P6OUT &= 0XBF; // DUAN close

P4OUT = 0XFF;

P5OUT |= 0X20;

P4OUT &= position[pos];

P5OUT &= 0XDF;

}

void delayms(uint t)

{

uint i;

while(t--)

for(i=110;i>0;i--);//进过参数的调整

}

//******************单通道单次转换***********/

void init_adc()

{

P6SEL |= 0X01;

ADC12CTL0 = SHT0_2 + ADC12ON;

ADC12CTL1 = SHP;

ADC12CTL0 |=ENC;

ADC12IE =0X01;

ADC12CTL0 |= ADC12SC;

}

void change()

{

uchar i=0;

while(temp)

{

result[4-i++] = temp%10;

temp /= 10;

}

}

void display()

{

uchar i;

for(i=0;i<4;i++)

{

show(i,result[i]);

delayms(2);

}

}

void main(void)

{

WDTCTL = WDTPW + WDTHOLD;

P6DIR |= BIT2;

P6OUT |= BIT2;

_EINT();

init_adc();

P6DIR |= 0X40; // p6^6 output

P5DIR |=0X20; // P5^5 OUTPUT

P4DIR = 0XFF; // P4 OUTPUT

  

while(1)

{

ADC12CTL0 |= ADC12SC; //BEGAIN TRANSFER

change();

display();

}

  

}

#pragma vector = ADC12_VECTOR

__interrupt void adc12(void)

{

temp = ADC12MEM0;

  

}

编程小号
上一篇 2025-02-15 19:51
下一篇 2025-02-24 15:46

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/58386.html