原创 ATmega16的软件端口模拟SPI方式控制TLC5615实现DAC

2009-6-26 18:47 6017 10 12 分类: MCU/ 嵌入式

/********************************************************************
//Title:ATmega16的SPI方式控制TLC5615DAC程序
//Target : M16
//Crystal: 8.0000Mhz
//Author:borlittle
//Time:2009-5-25 11:20:32
//Function:ATmega16的软件端口模拟SPI方式控制TLC5615实现DAC
//Note:


*********************************************************************/
#include <iom16v.h>
#include <macros.h>
#include "io_bit_field_16.h"


#define uchar unsigned char
#define uint unsigned int


#define GET_BIT(x,y) ((x&(0x0001<<y))==0?0:1)     


#define dout IOA0o  //PA0为SPI输出数据
#define clk  IOA1o   //PA1为SPI时钟
#define css  IOA2o  //PA2为SPI选通


#define din  IOA3i   //PA3为SPI输入数据



/*********************************************************************
//硬件连接图
//      ATmega16                 TLC5615          
//            PA0(dout)--> DIN            VDD  -->+5V
//            PA1 (clk)--> SCLK           OUT  -->OUT
//            PA2 (css)--> CS             REFIN<--VREF
//            PA3 (din)--> DOUT           AGND -->GND
//TLC5615:最快更新率为1.21MHz,并行输入输出的1O位DAC寄存器,
//非级联方式,12-Bit Input Data Sequence:当片选 CS为低电平时,
//串行输人数据被移人l2位移位寄存器,在每一个SCLK时钟的上升
//沿将DIN的一位数据移人12位移寄存器。
//二进制最高有效位最先被移人(主机需要先发最高位)。接着CS的上
//升沿将12位移位寄存器的1O位有效数据锁存于lO位DAC寄存器,供DAC电路进行转换?
//当片选CS为高电平时,串行输人数据不能被移人l2位移位寄存器。
//注意CS的上升和下降都必须发生在SCLK为低电平期间 
//         INPUT                       OUTPUT(VOLTAGE)    VREFIN="2".510v时实测输出
//   1111 1111 11(00)=0X0FFC       2(VREFIN)1023/1024          4.950v
//   1000 0000 01(00)=0X804        2(VREFIN) 513/1024          2.513v
//   1000 0000 00(00)=0X800        2(VREFIN) 512/1024 =VREFIN  2.510v
//   0100 0000 00(00)=0X400        2(VREFIN) 256/1024          1.256v
//   0011 1111 11(00)=0X3FC        2(VREFIN) 255/1024          1.250v
//   0000 0000 11(00)=0X0C         2(VREFIN)   3/1024          1.162v
//   0000 0000 10(00)=0X08         2(VREFIN)   2/1024          0.112v
//   0000 0000 01(00)=0X04         2(VREFIN)   1/1024          0.008v   增值约为5mV/1
//   0000 0000 00(00)=0            0 V      (不用DAC转换时将其置此值以减少功耗)       
************************************************************/
/*****************延时1.008毫秒子函数*******************/
void delay_1ms(void)
{
 uint i;
for(i=1;i<(8*143-2);i++) //8为晶振频率
;
}
/****************延时N毫秒子函数****************/
void delay_nms(uint n)
{
uint i;
for(i=0;i<n;i++)
delay_1ms();
}
/****************延时1秒子函数****************/
void delay_nthms(uint n)
{
uint i,j=1000*n;
for(i=0;i<j;i++)
delay_1ms();
}
/**********************SPI收发子函数*********************************************/
uint SPI_Sendx_Receivex(uint data_16 ,uchar x,uchar LSB0_MSB1,uchar clk_TRAN_UPD_EDGE)
//data_16的低x位有效,LSB0_MSB1为0低位先发,为1高位先发
//接收x位数据,先收的数据放高位,返回值低x位有效
//clk_TRAN_UPD_EDGE=1上升沿发数据,(从机采样)下降沿收从机更新数据
//clk_TRAN_UPD_EDGE=0下降沿发数据,(从机采样)上升沿收从机更新数据
{
uchar i,position;
uint receive="0";



if(LSB0_MSB1)  //发送数据处理
{position=15;
data_16<<=(18-x);
}
else position="0";


clk=!clk_TRAN_UPD_EDGE;//时钟下降沿,拉低
css=0;//选通


for(i=0;i<x;i++)
{
receive<<=1;
dout=GET_BIT((data_16),(position));//发送一位数据
receive|=din;
clk=clk_TRAN_UPD_EDGE;  


if(LSB0_MSB1)         //准备下一个高位先发
data_16<<=1;
else data_16>>=1;
 
clk=!clk_TRAN_UPD_EDGE;//更新数据
}
//恢复端口初始状态
css=1;//数据锁存
dout=0;
clk=1;
return receive;
}


void port_init(void)
{
 PORTA = 0x7F;   
 DDRA  = 0x7F; 
 DDRA0=1;//dout输出
 DDRA1=1;//clk输出
 DDRA2=1;//css选通输出
 DDRA3=0;//din输入
 //端口状态初始化
 dout=0;
 css=1;
 clk=1;
}



void main(void)
{
 uint datad;
 uint cd="512";
 //delay_nms(1);
 //delay_nthms(1);
 //cd<<=2;
 port_init();
 datad=SPI_Sendx_Receivex(cd,12,1,1);//传输10位数据,高位先发,上升沿发送?
  while(1)
  {
  /*
  //输出电压递增
   for(cd=0;cd<432;cd++)//不可用cd=i,因为赋值时将有错误
   { 
   cd++; 
   //cd++;
   datad="SPI"_Sendx_Receivex(cd,12,1,1);//传输10位数据,高位先发,上升沿发送,
   delay_nms(400);
  
  }
  //输出电压递减
   for(cd=432;cd>0;cd--)
   {
    cd--;
 //cd--;
    datad="SPI"_Sendx_Receivex(cd,12,1,1);//传输10位数据,高位先发,上升沿发送,
   delay_nms(400);
   }
   */
  }


}


/*************************************************************************
//Title:位域定义-ATmega16
//Author:borlittle
//Time:2009-5-22 21:32:32
//Function:方便操作ATmega16的IO端口的位
//Note:IOA1i --A口bit1输入,DRA1---A口bit1方向设置 IOA1o--A口bit1输输出
//可参考iom16v.h寄存器定义
****************************************************************************/


#ifndef io_bit_field_16_H
#define io_bit_field_16_H
//
//位域定义结构体
typedef struct INT8_bit_struct
{
unsigned bit0:1;unsigned bit1:1;unsigned bit2:1;unsigned bit3:1;
unsigned bit4:1;unsigned bit5:1;unsigned bit6:1;unsigned bit7:1;
}bit_field;
//宏定义端口,各端口对应的寄存器地址
#define _PIND  0X30
#define _DDRD  0X31
#define _PORTD 0X32


#define _PINC  0X33
#define _DDRC  0X34
#define _PORTC 0X35


#define _PINB  0X36
#define _DDRB  0X37
#define _PORTB 0X38


#define _PINA  0X39
#define _DDRA  0X3A
#define _PORTA 0X3B
//宏定义每一位
#define IOA0i (*(volatile bit_field*)(_PINA)).bit0
#define DDRA0 (*(volatile bit_field*)(_DDRA)).bit0
#define IOA0o (*(volatile bit_field*)(_PORTA)).bit0
#define IOA1i (*(volatile bit_field*)(_PINA)).bit1
#define DDRA1 (*(volatile bit_field*)(_DDRA)).bit1
#define IOA1o (*(volatile bit_field*)(_PORTA)).bit1
#define IOA2i (*(volatile bit_field*)(_PINA)).bit2
#define DDRA2 (*(volatile bit_field*)(_DDRA)).bit2
#define IOA2o (*(volatile bit_field*)(_PORTA)).bit2
#define IOA3i (*(volatile bit_field*)(_PINA)).bit3
#define DDRA3 (*(volatile bit_field*)(_DDRA)).bit3
#define IOA3o (*(volatile bit_field*)(_PORTA)).bit3
#define IOA4i (*(volatile bit_field*)(_PINA)).bit4
#define DDRA4 (*(volatile bit_field*)(_DDRA)).bit4
#define IOA4o (*(volatile bit_field*)(_PORTA)).bit4
#define IOA5i (*(volatile bit_field*)(_PINA)).bit5
#define DDRA5 (*(volatile bit_field*)(_DDRA)).bit5
#define IOA5o (*(volatile bit_field*)(_PORTA)).bit5
#define IOA6i (*(volatile bit_field*)(_PINA)).bit6
#define DDRA6 (*(volatile bit_field*)(_DDRA)).bit6
#define IOA6o (*(volatile bit_field*)(_PORTA)).bit6
#define IOA7i (*(volatile bit_field*)(_PINA)).bit7
#define DDRA7 (*(volatile bit_field*)(_DDRA)).bit7
#define IOA7o (*(volatile bit_field*)(_PORTA)).bit7


#define IOB0i (*(volatile bit_field*)(_PINB)).bit0
#define DDRB0 (*(volatile bit_field*)(_DDRB)).bit0
#define IOB0o (*(volatile bit_field*)(_PORTB)).bit0
#define IOB1i (*(volatile bit_field*)(_PINB)).bit1
#define DDRB1 (*(volatile bit_field*)(_DDRB)).bit1
#define IOB1o (*(volatile bit_field*)(_PORTB)).bit1
#define IOB2i (*(volatile bit_field*)(_PINB)).bit2
#define DDRB2 (*(volatile bit_field*)(_DDRB)).bit2
#define IOB2o (*(volatile bit_field*)(_PORTB)).bit2
#define IOB3i (*(volatile bit_field*)(_PINB)).bit3
#define DDRB3 (*(volatile bit_field*)(_DDRB)).bit3
#define IOB3o (*(volatile bit_field*)(_PORTB)).bit3
#define IOB4i (*(volatile bit_field*)(_PINB)).bit4
#define DDRB4 (*(volatile bit_field*)(_DDRB)).bit4
#define IOB4o (*(volatile bit_field*)(_PORTB)).bit4
#define IOB5i (*(volatile bit_field*)(_PINB)).bit5
#define DDRB5 (*(volatile bit_field*)(_DDRB)).bit5
#define IOB5o (*(volatile bit_field*)(_PORTB)).bit5
#define IOB6i (*(volatile bit_field*)(_PINB)).bit6
#define DDRB6 (*(volatile bit_field*)(_DDRB)).bit6
#define IOB6o (*(volatile bit_field*)(_PORTB)).bit6
#define IOB7i (*(volatile bit_field*)(_PINB)).bit7
#define DDRB7 (*(volatile bit_field*)(_DDRB)).bit7
#define IOB7o (*(volatile bit_field*)(_PORTB)).bit7


#define IOC0i (*(volatile bit_field*)(_PINC)).bit0
#define DDRC0 (*(volatile bit_field*)(_DDRC)).bit0
#define IOC0o (*(volatile bit_field*)(_PORTC)).bit0
#define IOC1i (*(volatile bit_field*)(_PINC)).bit1
#define DDRC1 (*(volatile bit_field*)(_DDRC)).bit1
#define IOC1o (*(volatile bit_field*)(_PORTC)).bit1
#define IOC2i (*(volatile bit_field*)(_PINC)).bit2
#define DDRC2 (*(volatile bit_field*)(_DDRC)).bit2
#define IOC2o (*(volatile bit_field*)(_PORTC)).bit2
#define IOC3i (*(volatile bit_field*)(_PINC)).bit3
#define DDRC3 (*(volatile bit_field*)(_DDRC)).bit3
#define IOC3o (*(volatile bit_field*)(_PORTC)).bit3
#define IOC4i (*(volatile bit_field*)(_PINC)).bit4
#define DDRC4 (*(volatile bit_field*)(_DDRC)).bit4
#define IOC4o (*(volatile bit_field*)(_PORTC)).bit4
#define IOC5i (*(volatile bit_field*)(_PINC)).bit5
#define DDRC5 (*(volatile bit_field*)(_DDRC)).bit5
#define IOC5o (*(volatile bit_field*)(_PORTC)).bit5
#define IOC6i (*(volatile bit_field*)(_PINC)).bit6
#define DDRC6 (*(volatile bit_field*)(_DDRC)).bit6
#define IOC6o (*(volatile bit_field*)(_PORTC)).bit6
#define IOC7i (*(volatile bit_field*)(_PINC)).bit7
#define DDRC7 (*(volatile bit_field*)(_DDRC)).bit7
#define IOC7o (*(volatile bit_field*)(_PORTC)).bit7


#define IOD0i (*(volatile bit_field*)(_PIND)).bit0
#define DDRD0 (*(volatile bit_field*)(_DDRD)).bit0
#define IOD0o (*(volatile bit_field*)(_PORTD)).bit0
#define IOD1i (*(volatile bit_field*)(_PIND)).bit1
#define DDRD1 (*(volatile bit_field*)(_DDRD)).bit1
#define IOD1o (*(volatile bit_field*)(_PORTD)).bit1
#define IOD2i (*(volatile bit_field*)(_PIND)).bit2
#define DDRD2 (*(volatile bit_field*)(_DDRD)).bit2
#define IOD2o (*(volatile bit_field*)(_PORTD)).bit2
#define IOD3i (*(volatile bit_field*)(_PIND)).bit3
#define DDRD3 (*(volatile bit_field*)(_DDRD)).bit3
#define IOD3o (*(volatile bit_field*)(_PORTD)).bit3
#define IOD4i (*(volatile bit_field*)(_PIND)).bit4
#define DDRD4 (*(volatile bit_field*)(_DDRD)).bit4
#define IOD4o (*(volatile bit_field*)(_PORTD)).bit4
#define IOD5i (*(volatile bit_field*)(_PIND)).bit5
#define DDRD5 (*(volatile bit_field*)(_DDRD)).bit5
#define IOD5o (*(volatile bit_field*)(_PORTD)).bit5
#define IOD6i (*(volatile bit_field*)(_PIND)).bit6
#define DDRD6 (*(volatile bit_field*)(_DDRD)).bit6
#define IOD6o (*(volatile bit_field*)(_PORTD)).bit6
#define IOD7i (*(volatile bit_field*)(_PIND)).bit7
#define DDRD7 (*(volatile bit_field*)(_DDRD)).bit7
#define IOD7o (*(volatile bit_field*)(_PORTD)).bit7


#endif

文章评论2条评论)

登录后参与讨论

用户571671 2009-7-1 11:01

楼上兄弟:上文中 /************************************************************************* //Title:位域定义-ATmega16 //Author:borlittle //Time:2009-5-22 21:32:32 //Function:方便操作ATmega16的IO端口的位 //Note:IOA1i --A口bit1输入,DRA1---A口bit1方向设置 IOA1o--A口bit1输输出 //可参考iom16v.h寄存器定义 ****************************************************************************/ 之后就是"io_bit_field_16.h"啊

用户920601 2009-6-27 03:02

楼主你好!能不能将"io_bit_field_16.h"贡献出来,共大家分享,谢谢!

用户104380 2008-3-23 22:33

因为要求输入的阻值是以千欧姆为单位的,所以查找千欧以下的阻值要输入小数了。呵呵,感觉yupc的提议很有意义,我一直没想到这点,还是集思广益啊,多谢了。

用户136065 2008-3-23 09:10

这个小工具还有待改进,我试用了一下,1K以下的电阻没有!!!功能只有查找相近的阻值,最好有这样一个功能,给出一个比例值,软件自动例出各种组合,这样对于设计模拟电路的人来说会很实用.
相关推荐阅读
用户571671 2011-12-14 21:33
关于“自制简单方便的51/avr单片机USB ISP下载线”的一些说明
   之前自己写的“自制简单方便的51/avr单片机USB ISP 下载线(硬件/软件部分)”得到了很多朋友的关注,大家也提出了一些问题。在这里我系统地说明一下:         1.用沁恒公...
用户571671 2010-06-14 20:28
完全解决Protel 99SE汉化版的菜单和功能丢失问题
Protel 99SE是一款极其优秀的PCB设计软件,小巧而又功能丰富,对于电脑的硬件的要求很低,那些凡能跑WINDOW98的电脑也可以运行。可惜有两个典型的不足:1.没有官方的汉化版,这对于懂英语的...
用户571671 2010-06-04 17:07
让Ubuntu10.04中的YAMAHA声卡发声
自己的电脑上已经装了Ubuntu10.04好久了,最近才发现它居然还是个“哑巴“,一直没有声音,不管是启动还是用各种播放器播放MP3歌曲均不能听到声音。都说Ubuntu对于设备的驱动已经做的很好了的,...
用户571671 2010-03-27 12:04
INTERL BUS和MOTOROLA BUS及其区别
在实际应用中用到的很多带并行总线的芯片的硬件连接、读写操作都分为INTERL BUS和MOTOROLA BUS(某些文献上又叫INTERL 模式和MOTOROLA 模式)这可以在相应的芯片手册上看到,...
用户571671 2010-02-27 13:57
LCD BackLight Control for utulinux 2440 LCD 背光控制
LCD BackLight Control for utulinux 2440 LCD 背光控制                     注解:borlittle仅供学习参考,源代码版权归原著者所有 ...
用户571671 2010-02-27 13:55
LED Example for utulinux 2440 LED测试示例
LED Example for utulinux 2440 LED测试示例注解:borlittle仅供学习参考,源代码版权归原著者所有<?xml:namespace prefix = o ns ...
我要评论
2
10
关闭 站长推荐上一条 /2 下一条