MSP430G2553 PCF8591的IIC程序

2019-03-24 11:38发布

我现在想要通过单片机和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 编辑 ] 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
6条回答
星空暖暖的
2019-03-25 03:03
JASON0916 发表于 2013-11-24 19:17
以上是我用51程序改过来的,可以通过按1.3的按键控制输出电压。希望能帮到以后看到这个贴的各位。加油!

这个程序经检验没有错误,但是为什么耗时很长呢,我用pcf8591产生正弦波,产生的频率特别低,最高只有30Hz,不知道怎么回事?

一周热门 更多>

相关问题

    相关文章