打印
[DemoCode下载]

TLC2543的51完美测试程序

[复制链接]
5327|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dongnanxibei|  楼主 | 2017-5-6 14:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

先上个仿真图,是不是高大上。
沙发
dongnanxibei|  楼主 | 2017-5-6 14:06 | 只看该作者
再上代码

#include<reg51.h>    //包含单片机寄存器的头文件
#include<intrins.h>  //包含_nop_()函数定义的头文件
unsigned char KeyVal; //声明键盘值的全局变量,只在程序开始时候初始化一次
sbit SDO=P2^3;
sbit SDI=P2^4;
sbit CS=P2^5;
sbit CLK=P2^6;
sbit EOC=P2^7;
sfr KeyPort=0x90;
////////////////////////////////////////////////////////////////////////////////
unsigned char code digit[10]={"0123456789"};   //定义字符数组显示数字
/*******************************************************************************
以下是对液晶模块的操作程序
*******************************************************************************/
sbit RS=P2^0;           //寄存器选择位,将RS位定义为P2.0引脚
sbit RW=P2^1;           //读写选择位,将RW位定义为P2.1引脚
sbit E=P2^2;            //使能信号位,将E位定义为P2.2引脚
sbit BF=P0^7;           //忙碌标志位,,将BF位定义为P0.7引脚


/*****************************************************
函数功能:延时若干毫秒
入口参数:n
***************************************************/
void delaynms(unsigned char n)
{
   unsigned char i,j,k;
   for(i=0;i<n;i++)
     for(j=0;j<2;j++)
       for(k=0;k<165;k++)
           ;
}
//***************************
/* void delay(unsigned char n)
{
unsigned char i;
for(i=0;i<n;i++)
_nop_();
}                                 */
/*****************************************************
函数功能:判断液晶模块的忙碌状态
返回值:result。result=1,忙碌;result=0,不忙
***************************************************/
bit BusyTest(void)
  {
    bit result;
    RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态
    RW=1;
    E=1;        //E=1,才允许读写
    _nop_();   //空操作
    _nop_();
    _nop_();
    _nop_();   //空操作四个机器周期,给硬件反应时间
    result=BF;  //将忙碌标志电平赋给result
    E=0;         //将E恢复低电平
    return result;
  }
/*************************************************************************
函数功能:将模式设置指令或显示地址写入液晶模块
入口参数:dictate为内容 ,choose为0时候进行指令操作,choose为1进行数据操作
*************************************************************************/
void WriteInstruction (unsigned char dictate ,bit choose)
{   
  while(BusyTest()==1);       //如果忙就等待

  RS=choose;                         //RS为0进行指令操作,RS为1进行数据操作。
  RW=0;   
  E=0;                   //E置低电平(根据表8-6,写指令时,E为高脉冲,
                        // 就是让E从0到1发生正跳变,所以应先置"0"
  _nop_();
  _nop_();               //空操作两个机器周期,给硬件反应时间
  P0=dictate;           //将数据送入P0口,即写入指令或地址
  _nop_();
  _nop_();
  _nop_();
  _nop_();               //空操作四个机器周期,给硬件反应时间
  E=1;                   //E置高电平
  _nop_();
  _nop_();
  _nop_();
  _nop_();               //空操作四个机器周期,给硬件反应时间
  E=0;                  //当E由高电平跳变成低电平时,液晶模块开始执行命令
}

/*****************************************************
函数功能:对LCD1602的显示模式进行初始化设置
***************************************************/
void LcdInitiate(void)
{
    delaynms(15);                    //延时15ms,首次写指令时应给LCD一段较长的反应时间
    WriteInstruction(0x38 , 0);     //显示模式设置:16×2显示,5×7点阵,8位数据接口
    delaynms(5);                   //延时5ms ,给硬件一点反应时间
    WriteInstruction(0x38 , 0);
    delaynms(5);                           //延时5ms ,给硬件一点反应时间
    WriteInstruction(0x38 , 0);           //连续三次,确保初始化成功
    delaynms(5);                         //延时5ms ,给硬件一点反应时间
    WriteInstruction(0x0c , 0);         //显示模式设置:显示开,无光标,光标不闪烁
    delaynms(5);                       //延时5ms ,给硬件一点反应时间
    WriteInstruction(0x06 , 0);       //显示模式设置:光标右移,字符不移
    delaynms(5);                     //延时5ms ,给硬件一点反应时间
    WriteInstruction(0x01 , 0);     //清屏幕指令,将以前的显示内容清除
    delaynms(5);                   //延时5ms ,给硬件一点反应时间
                                                          
}
/**************************************************************************
以下是显示的说明
**************************************************************************/
/*****************************************************
函数功能:显示字符串的函数
***************************************************/   
void display_string(unsigned char Str[],unsigned char addr)
{
    unsigned char i=0;
    WriteInstruction(addr|0x80 , 0);
    while(Str[i]!='\0')  //只要没有写到结束标志,就继续写
     {      
      WriteInstruction(Str[i] , 1);
      i++;                 //指向下一个字符   
     }
}

/*****************************************************
函数功能:显示一位数的函数
入口参数:x,addr
*****************************************************/
void display1(unsigned char x,unsigned char addr)
{


    WriteInstruction(addr|0x80 , 0);
    WriteInstruction(digit[x] , 1);
}
/************显示两位数的函数*****************/
void display2(unsigned char x,unsigned char addr)
{

   WriteInstruction(addr|0x80 , 0);
   WriteInstruction(digit[x/10] , 1); WriteInstruction(digit[x%10] , 1);
}
/*****************************************************
函数功能:显示四位数的函数
入口参数:x,addr

******************************************************/
void display4(unsigned int x,unsigned char addr)
{
unsigned char i,j,k,l;
i=x/1000;j=(x/100)%10;k=(x%100)/10;l=x%10;

WriteInstruction(addr|0x80 , 0);
WriteInstruction(digit[i] , 1); WriteInstruction(digit[j] , 1);        WriteInstruction(digit[k] , 1); WriteInstruction(digit[l] , 1);
}
/******************************************************
函数功能:AD转换模块Tlc2543的读取转换值的函数
入口参数:port(通道号)
******************************************************/
unsigned int read2543(unsigned char port)
{
unsigned int ad,i;
ad=0;
CLK=0;
CS=0;
port=port<<4;
for(i=0;i<12;i++)
{
if(SDO)
ad|=0x01;
SDI=(bit)(port&0x80);
CLK=1;
_nop_();_nop_();_nop_();
CLK=0;
_nop_();_nop_();_nop_();
port<<=1;
ad<<=1;
}
CS=1;
ad=ad>>1;
return(ad);
}
/***************键盘扫描程序*************************/
unsigned char key()
{

KeyPort=0xf0;
if((KeyPort&0xf0)!=0xf0)
delaynms(5);
if((KeyPort&0xf0)!=0xf0)
   {

    KeyPort=0xfe;
     switch(KeyPort)
            {
            case 0xee:KeyVal=0;break;                     
        case 0xde:KeyVal=1;break;                        
        case 0xbe:KeyVal=2;break;
        case 0x7e:KeyVal=3;break;
            }
        KeyPort=0xfd;
     switch(KeyPort)
            {
            case 0xed:KeyVal=4;break;                     
        case 0xdd:KeyVal=5;break;                        
        case 0xbd:KeyVal=6;break;
        case 0x7d:KeyVal=7;break;
            }
        KeyPort=0xfb;
     switch(KeyPort)
            {
            case 0xeb:KeyVal=8;break;                     
        case 0xdb:KeyVal=9;break;                        
        case 0xbb:KeyVal=10;break;
        case 0x7b:KeyVal=11;break;
            }
        KeyPort=0xf7;
     switch(KeyPort)
            {
            case 0xe7:KeyVal=12;break;                     
        case 0xd7:KeyVal=13;break;                        
        case 0xb7:KeyVal=14;break;
        case 0x77:KeyVal=15;break;
            }

   }
return KeyVal;  
}

/***************************************************
函数功能:主函数
***************************************************/
main(void)
{

    float Int,Dec,ad;        //分别储存转换后的整数部分与小数部分
    LcdInitiate();          //将液晶初始化
    delaynms(5);           //延时5ms给硬件一点反应时间
    display_string("Volt=",0x00);          //显示温度说明
    display_string(".",0x06);
    display_string("V",0x0b);
    display_string("InitialData=",0x40); //显示原始值提示
    while(1)
      {
                display2(key(),0x0e);
        ad=read2543(KeyVal);      //调用ad转换,传递通道号
        Int=(int)(ad/819);       //强制转换结果为整数。819==5/4095(*^__^*) ……
        Dec=((ad/819)-Int)*10000;
        display1(Int,0x05);        //显示整数部分
        display4(Dec,0x07);       //显示小数部分
        display4(ad,0x4c);       //输出原始值
        delaynms(250);          //延时250ms

      }
      
}


使用特权

评论回复
板凳
dongnanxibei|  楼主 | 2017-5-6 14:07 | 只看该作者
精华就是这个ADC芯片的驱动,就一个函数,神马初始化了,统统没有,一个搞定
/******************************************************
函数功能:AD转换模块Tlc2543的读取转换值的函数
入口参数:port(通道号)
******************************************************/
unsigned int read2543(unsigned char port)
{
unsigned int ad,i;
ad=0;
CLK=0;
CS=0;
port=port<<4;
for(i=0;i<12;i++)
{
if(SDO)
ad|=0x01;
SDI=(bit)(port&0x80);
CLK=1;
_nop_();_nop_();_nop_();
CLK=0;
_nop_();_nop_();_nop_();
port<<=1;
ad<<=1;
}
CS=1;
ad=ad>>1;
return(ad);
}


使用特权

评论回复
地板
dongnanxibei|  楼主 | 2017-5-6 14:08 | 只看该作者
或者采用高密度版本的驱动也是可以的,修改为

unsigned int Tlc2543(unsigned char port)
{
unsigned char i=0;     //定义时候初始化变量有助于压缩内存
unsigned int ad=0;    //初始化输出存储变量
CS=0;                //操作开始
CLK=0;
port<<=4;
port<<=4;
for(i=0;i<12;i++)
{ ad<<=1;               //空出最低位
   ad|=SDO;              //在下降沿取出输出数据寄存器的值
   SDI=(port&0x80);      // 取出最高位在上升沿发送到数据输入寄存器
   CLK=1;               //上升沿
   port<<=1;
   CLK=0;                 //下降沿
}
while(!EOC) continue;   //转换结束后再进入下一轮扫描。
return (ad);
}
是不是更简单?
实现的方式就是把需要延时的地方用执行代码替换,也就是传说中的统筹方法。哈哈。

使用特权

评论回复
5
dongnanxibei|  楼主 | 2017-5-6 14:10 | 只看该作者
奉上Proteus和源码程序,以及HEX。
adc2543.zip (28.81 KB)



使用特权

评论回复
6
dongnanxibei|  楼主 | 2017-5-6 14:10 | 只看该作者
最后补上浓缩版的
完美tlc2543.rar (1.06 KB)



使用特权

评论回复
7
dongnanxibei|  楼主 | 2017-5-6 14:26 | 只看该作者
之前有人发帖说明明是一半啊,怎么显示还带小数啊,这个就是四舍五入的问题了,因此如果对这个发愁,就建议数据转换成四舍五入保留两位小数的显示就OK了。

使用特权

评论回复
8
yiyigirl2014| | 2017-5-6 20:53 | 只看该作者
可以作为学习8位机的参考了。

使用特权

评论回复
9
稳稳の幸福| | 2017-5-6 23:20 | 只看该作者
代码写的真简单,漂亮。主要还是51没有ADC,如果有ADC的就不用这个了,不过这个写的方法可以用于控制其他的外设参考。

使用特权

评论回复
10
数传无线| | 2017-5-7 13:07 | 只看该作者
不错

使用特权

评论回复
11
wahahaheihei| | 2017-5-7 13:57 | 只看该作者
下载试了试,果然给力。

使用特权

评论回复
12
plan_1| | 2017-6-13 15:17 | 只看该作者
这里我说下,浓缩版的,
port<<=4;
port<<=4;
这里有点问题,不知道是不是楼主写错了,还是怎么的, 这样写的,只能读到0通道的值,设置其它通道无效,
取消一条port<<=4;就可以正常读取其它通道了

使用特权

评论回复
13
plan_1| | 2017-6-13 19:41 | 只看该作者
本帖最后由 plan_1 于 2017-6-13 19:42 编辑

现在还发现不能多次调用
void main()
{
while(1)
{
n=Tlc2543(1);通道1的值
n1=Tlc2543(2);通道2的值
n2=Tlc2543(3);通道3的值
//此时来获取的n、n1、n2的值,就不能正确读取,一直是乱跳动的数
}
}
当 只有n=Tlc2543(1);通道1的值   就是正常的。就是while语句中只读取一个通道的值,就是正常的
为什么呢, 求大神讲解啊,现在也正在研究这个芯片

使用特权

评论回复
14
L123i456| | 2019-7-9 11:23 | 只看该作者
顶顶顶

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

187

主题

3489

帖子

16

粉丝