我现在想要通过单片机和8591的da输出一个可调大小的稳定电压,但是研究了3个星期仍是没有弄懂,求各位大大指条明路,要崩溃了orz
包含的一个头函数,之后还贴了主程序,别的就没什么了,求各位大大给看看
/*******************************************************************************************
* File name : clock.c
* Creating time : 2012-7-11
* Author : 李帅
* pen-name : 亦然
* Organization : 济南大学
* Function : 该文件可用作模块儿化编程作为MSP430G2553的系统时钟配置文
件,在工程的主函数中直接调用Init_Clk()函数即可对系统时钟
进行配置。
* Declareing : 如有错误的地方请各位指出,交流。交流使我们共同进步!
* E-mail :
ls_core@sina.cn
* Contact way : QQ:1021480125 博客:
http://blog.sina.com.cn/lscore
**********************************************************************************************/
#include <msp430g2553.h>
/*DCOCTL 寄存器*/
/********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* DCO.2 CCO.1 DCO.0 MOD.4 MOD.3 MOD.2 MOD.1 MOD.0
* DCO.0——DCO.2定义8种频率之一,可分段调节DCOCLK频率,相邻两种频率相差10%。
* 而频率由注入直流发生器的电流定义。
* MOD.O——MOD.4定义在32个DCO周期中插入的fdco+l周期个数,而在余下的DCO周期
* 中为fDco周期,控制切换DCO和DCO+1选择的两种频率。如果DCO常数为7,表示已
* 经选择最高颂率,此时不能利用MOD.O-MOD.4进行频率调整。
* ********************************************************************************/
/*BCSCTL1 寄存器*/
/**********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* XT2OFF XTS DIVA.1 DIVA.0 XT5V Rse1.2 Rse1.1 Rse1.0
*XT2OFF控制 XT2 振荡器的开启与关闭。
*XT2OFF=0,XT2振荡器开启;
*XT2OFF=1,XT2振疡器关闭(默认XT2关闭)。
*XTS控制 LFXTl 工作模武,选择需结合实际晶体振荡器连接情况。
*XTS=0,LFXTl工作在低频模式 (默认低频模式);
*XTS=1,LFXTl工作在高频模式(必须连接有相应高频时钟源)。
*DIVA.0,DIVA.l控制ACLK分频。
*0 不分频(默认不分频);
*1 2分频;
*2 4分频;
*3 8分频。
*XT5V此位设置为0。
*Rse1.0,Rsel.l,Rse1.2三位控制某个内部电阻以决定标称频率。
*Rse1=0,选择最低的频率;
*Rse1=7,选择最低的标称频率;
***********************************************************************************/
/*BCSCTL2 寄存器*/
/***********************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
*SELM.1 SELM.0 DIVM.1 DIVM.0 SELS DIVS.1 DIVS.0 DCOR
*SELM.1,SELM.0选择 MCLK 时钟源。
*0 时钟源为 DCOLCK(默认时钟源);
*1 时钟源为DCOCLK ;
*2 时钟源为LFXTlCLK;
*3 时钟源为 LFXT1CLK 。
*DIVM.1,DlVM.0选择 MCLK 分频。
*0 1分频(默认MCLK=DCOCLK);
*1 2分频;
*2 4分频;
*3 8分频。
*DIVS.1,DIVS.0选择 SMCLK 分频。
*0 1分频(默认 SMCLK=MCLK);
*1 2分频;
*2 4分频;
*3 8分频。
************************************************************************************/
/*BCSCTL3 寄存器*/
/************************************************************************************
* bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
* XT2S1 XT2S0 LFXT1S1 LFXT1S0 XCAP1 XCAP0 XT2OF LFXT1OF
* XT2S1和XT2S0(2553不支持)
* LFXT1S1和LFXT1S0选择LFXT1的范围。
* XCAP1和XCAP0选择LFXT1的匹配电容
* 00 1pf
* 01 6pf
* 10 10pf
* 11 12.5pf
************************************************************************************/
/****************************************************************************************
* 静态函数声明
********************************************************************/
static void DcoClkSet(unsigned char x,unsigned char y); //msp430g2553datasheet P30
static void MClkSet(unsigned char Div);
static void SMClkSet(unsigned char Div);
static void AClkSet(unsigned char Div);
/************************************************************************
* 函数名 : DcoClkSet
* 函数功能 : 对时钟DCOCLK进行配置
* 函数形参 : 传入的形参为x和y,其值参考2553datsheet第28页中DCO频率表
* 函数返回值 : 无
************************************************************************/
void DcoClkSet(unsigned char x,unsigned char y) // msp430g2553datasheet P30
{
DCOCTL &=~( 0xFF);
BCSCTL1 &=~( 0xFF);
unsigned char temp=(x<<4)+y;
switch(temp){
case 0x00: {
DCOCTL &=~( DCO0 + DCO1 + DCO2);
BCSCTL1 &=~( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
case 0x03: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 &=~( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
case 0x13: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 );
break;
}
case 0x23: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 );
break;
}
case 0x33: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 );
break;
}
case 0x43: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL2);
break;
}
case 0x53: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL2 );
break;
}
case 0x63: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 + RSEL2 );
break;
}
case 0x73: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL2 );
break;
}
case 0x83: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL3);
break;
}
case 0x93: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0+ RSEL3);
break;
}
case 0xA3: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 + RSEL3);
break;
}
case 0xB3: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL3);
break;
}
case 0xC3: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL2 + RSEL3);
break;
}
case 0xD3: {
DCOCTL |= ( DCO0 + DCO1 );
DCOCTL |= ( MOD4 + MOD3 + MOD2 + MOD1 + MOD0 );//微调DCOCLK
BCSCTL1 |= ( RSEL0 + RSEL2 + RSEL3);
break;
}
case 0xE3: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL1 + RSEL2 + RSEL3);
break;
}
case 0xF3: {
DCOCTL |= ( DCO0 + DCO1 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
case 0xF7: {
DCOCTL |= ( DCO0 + DCO1 + DCO2 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL2 + RSEL3);
break;
}
default: {
DCOCTL |= ( DCO0 + DCO1 + DCO2 );
BCSCTL1 |= ( RSEL0 + RSEL1 + RSEL2 + RSEL3);
}
}
}
/********************************************************************
* 函数名 : MClkSet
* 函数功能 : 对时钟MCLK进行配置
* 函数形参 : 传入的形参为Div,对时钟源DCOCLK进行Div分频
* 函数返回值 : 无
********************************************************************/
void MClkSet(unsigned char Div)
{
BCSCTL2 &= ~(SELM1+SELM0); //select DCOCLK for MCLK
switch(Div){ //1分频
case 0x01:{
BCSCTL2 &=~(DIVM1 + DIVM0);
break;
}
case 0x02:{ //2分频
BCSCTL2 &=~(DIVM1 + DIVM0);
BCSCTL2 |=DIVM0;
break;
}
case 0x04:{ //4分频
BCSCTL2 &=~(DIVM1 + DIVM0);
BCSCTL2 |=DIVM1;
break;
}
case 0x08:{ //8分频
BCSCTL2 |=(DIVM1 + DIVM0);
break;
}
default :{ //默认不分频
BCSCTL2 &=~(DIVM1 + DIVM0);
}
}
}
/********************************************************************
* 函数名 : SMClkSet
* 函数功能 : 对时钟MCLK进行配置
* 函数形参 : 传入的形参为Div,对时钟源DCOCLK进行Div分频
* 函数返回值 : 无
********************************************************************/
void SMClkSet(unsigned char Div)
{
BCSCTL2 &= ~(SELM1+SELM0); //select DCOCLK for SMCLK
switch(Div){
case 0x01:{ //1分频
BCSCTL2 &=~(DIVS_3);
break;
}
case 0x02:{ //2分频
BCSCTL2 &=~(DIVS_3);
BCSCTL2 |=(DIVS_1);
break;
}
case 0x04:{ //4分频
BCSCTL2 &=~(DIVS_3);
BCSCTL2 |=(DIVS_2);
break;
}
case 0x08:{ //8分频
BCSCTL2 |=(DIVS_3);
break;
}
default :{ //默认不分频
BCSCTL2 &=~(DIVS_3);
}
}
}
/********************************************************************
* 函数名 : AClkSet
* 函数功能 : 对时钟MCLK进行配置
* 函数形参 : 传入的形参为Div,对时钟源LFXT1CLK进行Div分频
* 函数返回值 : 无
********************************************************************/
void AClkSet(unsigned char Div)
{
BCSCTL1 &=~(XTS); //low-frequency mode
switch(Div){
case 0x01:{ //1分频
BCSCTL1 &=~(DIVA_3);
break;
}
case 0x02:{ //2分频
BCSCTL1 &=~(DIVA_3);
BCSCTL1 |=(DIVA_1);
break;
}
case 0x04:{ //4分频
BCSCTL1 &=~(DIVA_3);
BCSCTL1 |=(DIVA_2);
break;
}
case 0x08:{ //8分频
BCSCTL1 |=(DIVA_3);
break;
}
default :{ //默认不分频
BCSCTL1 &=~(DIVA_3);
}
}
BCSCTL3 |= XT2S0 + LFXT1S0 + XCAP_3; //配置ACLK匹配电容
}
/********************************************************************
* 名称 : Init_Clk()
* 功能 : MSP430时钟系统初始化程序
* 输入 : 无
* 返回值 : 无
********************************************************************/
void Init_Clk() //时钟系统设置
{
DcoClkSet(13,3); //7.84MHz 2553datasheet 第28页
AClkSet(0x01); //1分频LFXT1CLK
SMClkSet(0x01); //1分频DCOCLK
MClkSet(0x01); //1分频DCOCLK
}
/*********************** end of file *************************/
主程序
#include <MSP430G2553.h>
#include "clock.h"
#define SDA BIT5 //P1.5输出SDA,顺带之后是1.4输出clk
#define SCL BIT4
char PCF8591_WRITE=0X90;//从地址字节
char VALUE1=0X90;//控制字节
char VALUE2=0X40;//AD字节,功能上用不着,不过根据数据手册看是必须要输入的
static int TIME=0; //后面用来计算按了几次按键
//先定义一个从机地址看看能不能行
void I2C_SET_SDA_HIGH(void)
{
//将sda设置为输出模式
P1DIR |=SDA;
//sda管教输出为高电平
P1OUT |=SDA;
_NOP();
_NOP();
return;
}
void I2C_SET_SDA_LOW(void)
{
//将SDA设置为输出模式
P1DIR |=SDA;
//sda管教输出为低电平
P1OUT &= ~(SDA);
_NOP();
_NOP();
return;
}
void I2C_SET_SCK_HIGH(void)
{
//将SCL设置为输出模式
P1DIR |= SCL;
//SCL管脚输出为高电平
P1OUT |= SCL;
_NOP();
_NOP();
}
void I2C_SET_SCK_LOW(void)
{
//将scl设置为输出模式
P1DIR |=SCL;
//scl管教输出为低电平
P1OUT &= ~(SCL);
_NOP();
_NOP();
}
void I2C_START(void)
{
int I;
//sda管脚输出为高电平
I2C_SET_SDA_HIGH();
//延迟一点时间
for(I=5;I>0;I--);
//scl管脚输出为高电平
I2C_SET_SCK_HIGH();
for(I=5;I>0;I--);
//sda管脚输出为低电平
I2C_SET_SDA_LOW();
for(I=5;I>0;I--);
//scl管脚输出为低电平
I2C_SET_SCK_LOW();
}
void I2C_STOP(void)
{
int I;
//sda管脚输出为低电平
I2C_SET_SDA_LOW();
for(I=5;I>0;I--);
//scl管脚输出为低电平
I2C_SET_SCK_LOW();
for(I=5;I>0;I--);
//scl管教输出为高电平
I2C_SET_SCK_HIGH();
for(I=5;I>0;I--);
//sda管脚输出为高电平
I2C_SET_SDA_HIGH();
for(I=5;I>0;I--);
//scl管教输出为低电平
I2C_SET_SCK_LOW();
//毫秒为单位,8MHZ为主时钟
unsigned long NCOUNT;
unsigned long J;
NCOUNT = 2667;
for(I=10;I>0;I--)
{
for(J=NCOUNT;J>0;J--);
}
}
void I2C_TXBYTE(int NVALUE)
{
int I;
int J;
for(I=0;I<8;I++)
{
if(NVALUE & 0x80)
{
I2C_SET_SDA_HIGH();
}
else
{
I2C_SET_SDA_LOW();
}
for(J=30;J>0;J--);
I2C_SET_SCK_HIGH();
NVALUE <<=1;
for(J=30;J>0;J--);
I2C_SET_SCK_LOW();
}
}
//获得ACK
void I2X_SETACK(void)
{
I2C_SET_SCK_LOW();
I2C_SET_SDA_LOW();
I2C_SET_SCK_HIGH();
I2C_SET_SCK_LOW();
return;
}
int I2C_GETACK(void)
{
int j;
int ntemp=0X00;
_NOP();
_NOP();
I2C_SET_SCK_LOW();
for(j=30;j>0;j--);
P1DIR &= ~(SDA);
I2C_SET_SCK_HIGH();
for(j=30;j>0;j--);
ntemp = (int)(P1IN & SDA);
I2C_SET_SCK_LOW();
return (ntemp & SDA);
}
//从机地址还不是很清楚怎么做,需要试验
int WRITESINGLEBYTE(char NADDR, char NVALUE)
{
int NTEMP = 0xA0;
//启动数据总线
I2C_START();
//发送控制字节
I2C_TXBYTE(NTEMP);
//等待ACK
NTEMP = I2C_GETACK();
if(NTEMP & BIT3)
return 0;
//发送地址字节
I2C_TXBYTE(NADDR);
NTEMP = I2C_GETACK();
if(NTEMP & BIT3)
return 0;
I2C_TXBYTE(NVALUE);
NTEMP = I2C_GETACK();
if(NTEMP & BIT3)
return 0;
//停止总线
I2C_STOP();
return (NTEMP & SDA);
}
/*void Init_CLK(void)
{
unsigned int i;
BCSCTL1 = 0X00; //将寄存器的内容清零
//XT2震荡器开启
//LFTX1工作在低频模式
//ACLK的分频因子为1
do
{
// 清除OSCFault标志
IFG1 &= ~OFIFG;
for (i = 0x20; i > 0; i--);
}
while ((IFG1 & OFIFG) == OFIFG);// 如果OSCFault =1
//将寄存器的内容清零
BCSCTL2 = 0X00;
//MCLK的时钟源为TX2CLK,分频因子为1
BCSCTL2 += SELM1;
//SMCLK的时钟源为TX2CLK,分频因子为1
BCSCTL2 += SELS;
}*/
void main(void)
{
WDTCTL = WDTPW +WDTHOLD; // 关闭看门狗
//控制时钟,输出给clk线
if (CALBC1_1MHZ ==0xFF || CALDCO_1MHZ == 0xFF)
{
while(1); // If calibration constants erased
// do not load, trap CPU!!
}
//8Mhz
Init_Clk();
P1DIR |=BIT4+BIT5;
P1SEL |=BIT4; //配置P1.4为SMCLK输出功能
P1SEL2 |= BIT4;
WRITESINGLEBYTE(PCF8591_WRITE, VALUE1);
WRITESINGLEBYTE(PCF8591_WRITE, VALUE2);
WRITESINGLEBYTE(PCF8591_WRITE, 0xC0);//给一个初始电压
//按键模块,引发中断
P1DIR&=~BIT3;//P1.3按键输入
P1REN |= BIT3;//打开上拉
P1IE |=BIT3; //使能按键P1.3引脚中断
P1IES&=~BIT3; //中断触发方式为上升降沿
P1OUT |= BIT3;
_EINT();//开总中断
}
//中断
#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
char NVALUE = 0xC0;//按照vref=0,vcc=3.3v来算,初始电压2.5v
for(;;)
{
if(P1IFG&BIT3)
{
for(int i=0;i<50;i++);//消抖
TIME++;
P1IFG&=~BIT3;
}
else
P1IFG=0x00; //清除中断标志位
NVALUE += TIME*500;//调节用
WRITESINGLEBYTE(PCF8591_WRITE, NVALUE);//更新输出
}
}
不胜感激!
[
本帖最后由 JASON0916 于 2013-11-21 23:15 编辑 ]
此帖出自
小平头技术问答
以下是改过之后的官方例程,我只是改了从机地址(0x90)和控制位地址(0x40),别的都没改过
//******************************************************************************
// MSP430G2xx3 Demo - USCI_B0 I2C Master Interface to DAC8571, Write
//
// Description: Using UCB0TXIE, a continuous sine wave is output to the
// external DAC using a 16-point look-up table. Only one start condition
// is executed. Data is handled by the ISR and the CPU is normally in LPM0.
// ACLK = n/a, MCLK = SMCLK = BRCLK = default DCO = ~1.2MHz
//
// MSP430G2xx3 DAC8571
// ------------------ ------------
// -|XIN P1.7/UCB0SDA|<--------------->|SDA |
// | P1.6/UCB0SCL|---------------->|SCL I2C |
// -|XOUT | | SLAVE |
// | I2C MASTER | GND|A0 |
//
//
// DAC8571 I2C address = 0x4C (A0 = GND)
//
// D. Dang
// Texas Instruments Inc.
// February 2011
// Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************
#include "msp430g2553.h"
const unsigned char Sine_Tab[] = // 16 Point 16-bit Sine Table
{
0xFF, // MSB Word 0
0xFF, // LSB
0xF6, // MSB Word 1
0x40, // LSB
0xDA, // MSB Word 2
0x81, // LSB
0xB0, // MSB Word 3
0xFA, // LSB
0x7F, // MSB Word 4
0xFF, // LSB
0x4F, // MSB Word 5
0x03, // LSB
0x25, // MSB Word 6
0x7C, // LSB
0x09, // MSB Word 7
0xBD, // LSB
0x00, // MSB Word 8
0x00, // LSB
0x09, // MSB Word 9
0xBD, // LSB
0x25, // MSB Word 10
0x7C, // LSB
0x4F, // MSB Word 11
0x03, // LSB
0x7F, // MSB Word 12
0xFE, // LSB
0xB0, // MSB Word 13
0xFA, // LSB
0xDA, // MSB Word 14
0x81, // LSB
0xF6, // MSB Word 15
0x40 // LSB
};
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop Watchdog Timer
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0,1.6SCL
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0,1.7SDA
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x90; // Set slave address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE; // Enable TX ready interrupt
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
UCB0TXBUF = 0x40; // Write DAC control byte
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
// USCI_B0 Data ISR
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{
static unsigned char ByteCtr=0;
UCB0TXBUF = 0XFF ; // Transmit data byte
ByteCtr &= 0x1f; // Do not exceed table
}
求问各位大大
一周热门 更多>