[DemoCode下载] TLC2543的51完美测试程序

[复制链接]
 楼主| dongnanxibei 发表于 2017-5-6 14:05 | 显示全部楼层 |阅读模式
QQ截图20170506140507.png
先上个仿真图,是不是高大上。
 楼主| dongnanxibei 发表于 2017-5-6 14:06 | 显示全部楼层
再上代码

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


  19. /*****************************************************
  20. 函数功能:延时若干毫秒
  21. 入口参数:n
  22. ***************************************************/
  23. void delaynms(unsigned char n)
  24. {
  25.    unsigned char i,j,k;
  26.    for(i=0;i<n;i++)
  27.      for(j=0;j<2;j++)
  28.        for(k=0;k<165;k++)
  29.            ;
  30. }
  31. //***************************
  32. /* void delay(unsigned char n)
  33. {
  34. unsigned char i;
  35. for(i=0;i<n;i++)
  36. _nop_();
  37. }                                 */
  38. /*****************************************************
  39. 函数功能:判断液晶模块的忙碌状态
  40. 返回值:result。result=1,忙碌;result=0,不忙
  41. ***************************************************/
  42. bit BusyTest(void)
  43.   {
  44.     bit result;
  45.     RS=0;       //根据规定,RS为低电平,RW为高电平时,可以读状态
  46.     RW=1;
  47.     E=1;        //E=1,才允许读写
  48.     _nop_();   //空操作
  49.     _nop_();
  50.     _nop_();
  51.     _nop_();   //空操作四个机器周期,给硬件反应时间
  52.     result=BF;  //将忙碌标志电平赋给result
  53.     E=0;         //将E恢复低电平
  54.     return result;
  55.   }
  56. /*************************************************************************
  57. 函数功能:将模式设置指令或显示地址写入液晶模块
  58. 入口参数:dictate为内容 ,choose为0时候进行指令操作,choose为1进行数据操作
  59. *************************************************************************/
  60. void WriteInstruction (unsigned char dictate ,bit choose)
  61. {   
  62.   while(BusyTest()==1);       //如果忙就等待

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

  81. /*****************************************************
  82. 函数功能:对LCD1602的显示模式进行初始化设置
  83. ***************************************************/
  84. void LcdInitiate(void)
  85. {
  86.     delaynms(15);                    //延时15ms,首次写指令时应给LCD一段较长的反应时间
  87.     WriteInstruction(0x38 , 0);     //显示模式设置:16×2显示,5×7点阵,8位数据接口
  88.     delaynms(5);                   //延时5ms ,给硬件一点反应时间
  89.     WriteInstruction(0x38 , 0);
  90.     delaynms(5);                           //延时5ms ,给硬件一点反应时间
  91.     WriteInstruction(0x38 , 0);           //连续三次,确保初始化成功
  92.     delaynms(5);                         //延时5ms ,给硬件一点反应时间
  93.     WriteInstruction(0x0c , 0);         //显示模式设置:显示开,无光标,光标不闪烁
  94.     delaynms(5);                       //延时5ms ,给硬件一点反应时间
  95.     WriteInstruction(0x06 , 0);       //显示模式设置:光标右移,字符不移
  96.     delaynms(5);                     //延时5ms ,给硬件一点反应时间
  97.     WriteInstruction(0x01 , 0);     //清屏幕指令,将以前的显示内容清除
  98.     delaynms(5);                   //延时5ms ,给硬件一点反应时间
  99.                                                           
  100. }
  101. /**************************************************************************
  102. 以下是显示的说明
  103. **************************************************************************/
  104. /*****************************************************
  105. 函数功能:显示字符串的函数
  106. ***************************************************/   
  107. void display_string(unsigned char Str[],unsigned char addr)
  108. {
  109.     unsigned char i=0;
  110.     WriteInstruction(addr|0x80 , 0);
  111.     while(Str[i]!='\0')  //只要没有写到结束标志,就继续写
  112.      {      
  113.       WriteInstruction(Str[i] , 1);
  114.       i++;                 //指向下一个字符   
  115.      }
  116. }

  117. /*****************************************************
  118. 函数功能:显示一位数的函数
  119. 入口参数:x,addr
  120. *****************************************************/
  121. void display1(unsigned char x,unsigned char addr)
  122. {


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

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

  135. ******************************************************/
  136. void display4(unsigned int x,unsigned char addr)
  137. {
  138. unsigned char i,j,k,l;
  139. i=x/1000;j=(x/100)%10;k=(x%100)/10;l=x%10;

  140. WriteInstruction(addr|0x80 , 0);
  141. WriteInstruction(digit[i] , 1); WriteInstruction(digit[j] , 1);        WriteInstruction(digit[k] , 1); WriteInstruction(digit[l] , 1);
  142. }
  143. /******************************************************
  144. 函数功能:AD转换模块Tlc2543的读取转换值的函数
  145. 入口参数:port(通道号)
  146. ******************************************************/
  147. unsigned int read2543(unsigned char port)
  148. {
  149. unsigned int ad,i;
  150. ad=0;
  151. CLK=0;
  152. CS=0;
  153. port=port<<4;
  154. for(i=0;i<12;i++)
  155. {
  156. if(SDO)
  157. ad|=0x01;
  158. SDI=(bit)(port&0x80);
  159. CLK=1;
  160. _nop_();_nop_();_nop_();
  161. CLK=0;
  162. _nop_();_nop_();_nop_();
  163. port<<=1;
  164. ad<<=1;
  165. }
  166. CS=1;
  167. ad=ad>>1;
  168. return(ad);
  169. }
  170. /***************键盘扫描程序*************************/
  171. unsigned char key()
  172. {

  173. KeyPort=0xf0;
  174. if((KeyPort&0xf0)!=0xf0)
  175. delaynms(5);
  176. if((KeyPort&0xf0)!=0xf0)
  177.    {

  178.     KeyPort=0xfe;
  179.      switch(KeyPort)
  180.             {
  181.             case 0xee:KeyVal=0;break;                     
  182.         case 0xde:KeyVal=1;break;                        
  183.         case 0xbe:KeyVal=2;break;
  184.         case 0x7e:KeyVal=3;break;
  185.             }
  186.         KeyPort=0xfd;
  187.      switch(KeyPort)
  188.             {
  189.             case 0xed:KeyVal=4;break;                     
  190.         case 0xdd:KeyVal=5;break;                        
  191.         case 0xbd:KeyVal=6;break;
  192.         case 0x7d:KeyVal=7;break;
  193.             }
  194.         KeyPort=0xfb;
  195.      switch(KeyPort)
  196.             {
  197.             case 0xeb:KeyVal=8;break;                     
  198.         case 0xdb:KeyVal=9;break;                        
  199.         case 0xbb:KeyVal=10;break;
  200.         case 0x7b:KeyVal=11;break;
  201.             }
  202.         KeyPort=0xf7;
  203.      switch(KeyPort)
  204.             {
  205.             case 0xe7:KeyVal=12;break;                     
  206.         case 0xd7:KeyVal=13;break;                        
  207.         case 0xb7:KeyVal=14;break;
  208.         case 0x77:KeyVal=15;break;
  209.             }

  210.    }
  211. return KeyVal;  
  212. }

  213. /***************************************************
  214. 函数功能:主函数
  215. ***************************************************/
  216. main(void)
  217. {

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

  235.       }
  236.       
  237. }


 楼主| dongnanxibei 发表于 2017-5-6 14:07 | 显示全部楼层
精华就是这个ADC芯片的驱动,就一个函数,神马初始化了,统统没有,一个搞定
  1. /******************************************************
  2. 函数功能:AD转换模块Tlc2543的读取转换值的函数
  3. 入口参数:port(通道号)
  4. ******************************************************/
  5. unsigned int read2543(unsigned char port)
  6. {
  7. unsigned int ad,i;
  8. ad=0;
  9. CLK=0;
  10. CS=0;
  11. port=port<<4;
  12. for(i=0;i<12;i++)
  13. {
  14. if(SDO)
  15. ad|=0x01;
  16. SDI=(bit)(port&0x80);
  17. CLK=1;
  18. _nop_();_nop_();_nop_();
  19. CLK=0;
  20. _nop_();_nop_();_nop_();
  21. port<<=1;
  22. ad<<=1;
  23. }
  24. CS=1;
  25. ad=ad>>1;
  26. return(ad);
  27. }


 楼主| dongnanxibei 发表于 2017-5-6 14:08 | 显示全部楼层
或者采用高密度版本的驱动也是可以的,修改为

  1. unsigned int Tlc2543(unsigned char port)
  2. {
  3. unsigned char i=0;     //定义时候初始化变量有助于压缩内存
  4. unsigned int ad=0;    //初始化输出存储变量
  5. CS=0;                //操作开始
  6. CLK=0;
  7. port<<=4;
  8. port<<=4;
  9. for(i=0;i<12;i++)
  10. { ad<<=1;               //空出最低位
  11.    ad|=SDO;              //在下降沿取出输出数据寄存器的值
  12.    SDI=(port&0x80);      // 取出最高位在上升沿发送到数据输入寄存器
  13.    CLK=1;               //上升沿
  14.    port<<=1;
  15.    CLK=0;                 //下降沿
  16. }
  17. while(!EOC) continue;   //转换结束后再进入下一轮扫描。
  18. return (ad);
  19. }
是不是更简单?
实现的方式就是把需要延时的地方用执行代码替换,也就是传说中的统筹方法。哈哈。
 楼主| dongnanxibei 发表于 2017-5-6 14:10 | 显示全部楼层
奉上Proteus和源码程序,以及HEX。
adc2543.zip (28.81 KB, 下载次数: 120)



 楼主| dongnanxibei 发表于 2017-5-6 14:10 | 显示全部楼层
最后补上浓缩版的
完美tlc2543.rar (1.06 KB, 下载次数: 87)



 楼主| dongnanxibei 发表于 2017-5-6 14:26 | 显示全部楼层
之前有人发帖说明明是一半啊,怎么显示还带小数啊,这个就是四舍五入的问题了,因此如果对这个发愁,就建议数据转换成四舍五入保留两位小数的显示就OK了。
yiyigirl2014 发表于 2017-5-6 20:53 | 显示全部楼层
可以作为学习8位机的参考了。
稳稳の幸福 发表于 2017-5-6 23:20 | 显示全部楼层
代码写的真简单,漂亮。主要还是51没有ADC,如果有ADC的就不用这个了,不过这个写的方法可以用于控制其他的外设参考。
数传无线 发表于 2017-5-7 13:07 来自手机 | 显示全部楼层
不错
wahahaheihei 发表于 2017-5-7 13:57 | 显示全部楼层
下载试了试,果然给力。
plan_1 发表于 2017-6-13 15:17 | 显示全部楼层
这里我说下,浓缩版的,
port<<=4;
port<<=4;
这里有点问题,不知道是不是楼主写错了,还是怎么的, 这样写的,只能读到0通道的值,设置其它通道无效,
取消一条port<<=4;就可以正常读取其它通道了
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语句中只读取一个通道的值,就是正常的
为什么呢, 求大神讲解啊,现在也正在研究这个芯片
L123i456 发表于 2019-7-9 11:23 | 显示全部楼层
顶顶顶
您需要登录后才可以回帖 登录 | 注册

本版积分规则

223

主题

3840

帖子

18

粉丝
快速回复 在线客服 返回列表 返回顶部