找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

51单片机控制74LS164芯片输出64位的数组

查看数: 5700 | 评论数: 19 | 收藏 2
关灯 | 提示:支持键盘翻页<-左 右->
    组图打开中,请稍候......
发布时间: 2019-2-12 02:37

正文摘要:

本帖最后由 izhonguo 于 2019-3-7 00:59 编辑 各位大神新年好,想请教一个简单的程序如何写。想利用51单片机的P00和P01两个串口输出一个16位的数组【0 0 0 1 1 1 0 0 ****】等数据,然后利用LS164这个芯片实现并 ...

回复

ID:213173 发表于 2019-3-14 08:46
本帖最后由 wulin 于 2019-3-14 13:17 编辑
izhonguo 发表于 2019-3-13 21:40
总工,您好,这周测试了一下实物,意识到AA开头的可能会出现一个问题,比如说发出来的数据开头不是AA,中 ...

izhonguo你好,很赞赏你勤于思考。给你的示例只是我随手写的,简单展示了自定义通讯协议的框架。实际运用的自定义通讯协议要比这复杂些。由于使用环境因素,数据头往往由好几个字节组成,甚至在数据头前加0x00无效数据引导以防数据头错码。验证有效数据的正确性是非常重要的措施。方法也很多,有用数据和、数据和取反+1、计算字节长度等等。目的都是为了保证有效数据的正确性。由于传输的数据帧包含的字节可能不确定,还要增加结束码等等。串口中断函数中还要有自动纪录字节长度,超时不等侯措施。
ID:475803 发表于 2019-3-7 21:33
wulin 发表于 2019-3-7 15:54
给你改了一下,已经实物验证,供参考。

多谢总工!我再仔细学习一遍。。。
总工牛逼!
ID:213173 发表于 2019-3-7 15:54
izhonguo 发表于 2019-3-7 00:53
总工,您好:
我自己学习了一下51单片机的串口接收程序,我想把您这个程序改进一下,
做到可以接收比 ...

给你改了一下,已经实物验证,供参考。

  1. //模拟数据:0数据头  1~8有效数据               9数据尾  
  2. //HEX模式:    AA     01 0A 02 0B 03 0C 04 0D       38
  3. #include <reg51.H>
  4. #define uint unsigned int
  5. #define uchar unsigned char
  6. sbit P_HC595_SER   = P0^0;//使用P0口需外接5~10K上拉电阻
  7. sbit P_HC595_SRCLK = P0^1;
  8. sbit P_HC595_RCLK  = P0^2;

  9. uchar table0[] ="OK\n";        //用于串口助手返回验证
  10. uchar table1[]="ERROR\n";//用于串口助手返回验证
  11. uchar dis_buf[10];                //串口接收缓存
  12. bit flag=0;                                        //接收完成标志
  13. /*******************串口初始化函数*************************/
  14. void URATinit()
  15. {  
  16.         PCON &= 0x7F;                //波特率不倍速9600
  17.         SCON = 0x50;                //8位数据,可变波特率
  18.         TMOD= 0x20;                        //设定定时器1为8位自动重装方式
  19.         TL1 = 0xFD;                        //设定定时初值
  20.         TH1 = 0xFD;                        //设定定时器重装值
  21.         ET1 = 0;                                //禁止定时器1中断
  22.         TR1 = 1;                                //启动定时器1
  23.         EA = 1;                                //开总中断
  24.         ES = 1;                                //开串口中断
  25. }

  26. /**************** 向HC595发送一个字节函数 ******************/
  27. void Send_595(uchar dat)
  28. {               
  29.         uchar i;
  30.         for(i=0;i<8;i++)
  31.         {
  32.                 dat <<= 1;
  33.                 P_HC595_SER  = CY; //溢出位赋值数据输出端
  34.                 P_HC595_SRCLK = 1; //移位时钟
  35.                 P_HC595_SRCLK = 0;
  36.         }
  37. }
  38. /**************** 向HC595发送八个字节函数 ******************/
  39. void DisplayScan()
  40. {        
  41.         uchar j;
  42.         for(j=0;j<8;j++)
  43.         {
  44.                 Send_595(dis_buf[j+1]);//向HC595发送一个字节
  45.         }
  46.         P_HC595_RCLK = 1;//锁存输出数据
  47.         P_HC595_RCLK = 0;
  48. }
  49. /**********串口发送函数*************/
  50. void SendOneByte(uchar i)
  51. {
  52.     SBUF = i;                //发送数据
  53.     while(!TI);        //等待发送完成
  54.     TI = 0;                        //发送中断请求标志位清0
  55. }
  56. /************数据解析程序*************/
  57. void analysis()
  58. {
  59.         uchar i,j=0;                //临时变量
  60.         if(flag==1)                //10个字节数据串接收完成
  61.         {
  62.                 ES=0;                        //关串口中断
  63.                 flag=0;                //接收完成标志清0
  64.                 for(i=0;i<8;i++)
  65.                 {
  66.                         j+=dis_buf[i+1];//读取缓存里8个字节有效数据和,溢出部分抛弃
  67.                 }
  68.                 if(dis_buf[9]==j)//验证数据和
  69.                 {
  70.                         for(i=0;i<3;i++)
  71.                         {
  72.                                 SendOneByte(table0[i]);//返回PC "OK"(用串口助手文本模式接收)
  73.                         }
  74.                         DisplayScan();    //向HC595发送缓存收到的8个有效字节
  75. //                        for(i=0;i<10;i++)//返回PC,缓存收到的10个字节(用串口助手HEX模式接收)
  76. //                        {
  77. //                                SendOneByte(dis_buf[i]);
  78. //                        }
  79.                 }
  80.                 else
  81.                 {
  82.                         for(i=0;i<6;i++)
  83.                         {
  84.                                 SendOneByte(table1[i]);//返回PC "ERROR"
  85.                         }
  86.                         for(i=0;i<10;i++)
  87.                         {
  88.                                 dis_buf[i]=0;                        //清空缓存
  89.                         }
  90.                 }
  91.                 ES=1;                                                //开串口中断
  92.         }
  93. }
  94. /*******主函数********/
  95. void main()
  96. {
  97.         P_HC595_SRCLK = 0;                        //初始化移位时钟端
  98.         P_HC595_RCLK  = 0;                        //初始化锁存输出端
  99.         URATinit();                                        //初始化串口
  100.         while(1)
  101.         {
  102.                 analysis();                                //数据解析程序
  103.         }
  104. }
  105. /*******************中断函数*************************/
  106. void receive() interrupt 4
  107. {
  108.         static uchar i=0;                //静态计数变量

  109.         RI=0;                                        //接收中断请求标志位清0
  110.         dis_buf[i]=SBUF;                //接收到的数据串保存在缓存数组中
  111.         if(dis_buf[0]==0xAA)        //验证数据头(起始位),否则重收覆盖
  112.         {
  113.                 i++;
  114.                 if(i>=10)
  115.                 {
  116.                         flag=1;                        //接收完成标志置1(完成1帧10bit)
  117.                         i=0;                        //计数变量清0
  118.                 }
  119.         }
  120. }  
复制代码



ID:475803 发表于 2019-3-7 00:53
wulin 发表于 2019-2-14 08:48
你的上述疑问是真实存在的,如果改用74HC595连级输出可以解决你的上述疑问。给你一个示例程序和仿真。

...

总工,您好:
我自己学习了一下51单片机的串口接收程序,我想把您这个程序改进一下,
做到可以接收比如说从XCOM这类软件发来的八个字符串(比如说1A2B3C4D),
然后写入到dis_buf[8]定义的这个定义的缓存数组中。下面这样子写正确吗?还望不吝赐教!谢谢!


  1. #include <reg51.H>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. sbit        P_HC595_SER   = P0^0;
  5. sbit        P_HC595_SRCLK = P0^1;
  6. sbit        P_HC595_RCLK  = P0^2;

  7. /*******************定义8个字节64 bit接收缓存数组*************************/
  8. uchar data dis_buf[8]={0};//初始化字符串

  9. /*******************串口初始化函数*************************/
  10. void   URATinit( )
  11. {  
  12.         TMOD=0x20;  
  13.         SCON=0x50;  
  14.         EA=1;  
  15.         ES=1;  
  16.         TR1=1;  
  17.         TH1=0xfd;  
  18.         TL1=0xfd;
  19. }

  20. /*******************中断函数*************************/
  21. void receive() interrupt 4
  22. {
  23.         uchar i;        
  24.         if(RI) { //PC机向单片机发送命令是否被识别      
  25.                 dis_buf[i]=SBUF;   
  26.                 RI=0; //清0准备下一次接收  
  27.         }
  28.         while(!TI);   
  29.         TI=0;  
  30.         i++;  
  31.         if(i>=8){ //防止大于8溢出
  32.                 i=0;  
  33.         }
  34. }  
  35. /**************** 向HC595发送一个字节函数 ******************/
  36. void Send_595(uchar dat)
  37. {               
  38.         uchar i;
  39.         for(i=0;i<8;i++)
  40.         {
  41.                 dat <<= 1;
  42.                 P_HC595_SER  = CY; //溢出位赋值数据输出端
  43.                 P_HC595_SRCLK = 1; //移位时钟
  44.                 P_HC595_SRCLK = 0;
  45.         }
  46. }
  47. /**************** 向HC595发送八个字节函数 ******************/
  48. void DisplayScan()
  49. {        
  50.         uchar j;
  51.         for(j=0;j<8;j++)
  52.         {
  53.                 Send_595(dis_buf[j]);//向HC595发送一个字节
  54.         }
  55.         P_HC595_RCLK = 1;//锁存输出数据
  56.         P_HC595_RCLK = 0;
  57. }

  58. void main()
  59. {
  60.         P_HC595_SRCLK = 0;//初始化移位时钟端
  61.         P_HC595_RCLK  = 0;//初始化锁存输出端
  62.         URATinit( );
  63.         DisplayScan();                //发送八个字节
  64.         while(1);
  65. }
复制代码



ID:383215 发表于 2019-2-21 13:34
izhonguo 发表于 2019-2-21 08:31
多谢经验分享,刚接触单片机,还需要多向各位大牛勤快请教。

不用谢!51单片机的P0口驱动LED、通过三极管驱动继电器,读开关状态之类的低速应用问题不大,高速读写的情况下就要注意了,比如I2C、SPI接口等等
ID:475803 发表于 2019-2-21 08:31
kmsj 发表于 2019-2-20 16:01
先不谈程序,51单片机的P0口是个非常扯淡的口,我的仿真器的仿真头排线在左边,插到目标板上P1和P3口就挡住 ...

多谢经验分享,刚接触单片机,还需要多向各位大牛勤快请教。
ID:477934 发表于 2019-2-20 17:42

标题与内容描述不符,内容描述与程序不符,程序中数据类型定义与实际需要不符,最终全体不服!
ID:383215 发表于 2019-2-20 16:01
先不谈程序,51单片机的P0口是个非常扯淡的口,我的仿真器的仿真头排线在左边,插到目标板上P1和P3口就挡住了,P1和P3口用起来就不太方便,P0和P2口没有被挡住,P0口在左上角,接线最方便,所以我经常用P0口仿真,直到有一次仿真74HC165,简简单单的移位程序,怎么都无法成功,搞的我焦头烂额,后来用AVR单片机仿真,一次就成功。突发奇想,用51单片机的P2口仿真74HC165,也是一次成功。要知道,51单片机的P0口仿真CD4094、CD4014、CD4021都能成功,就是74HC165不能成功,我编了一些方波程序看P0口和其它口的差别,发现P0口下拉能力弱,速度也很慢,要想用P0口仿真74HC165成功,最简单的方法就是降低速度,但是,如果使用和研究51单片机,少用和慎用P0口是少走弯路的重要方法的之一。

评分

参与人数 1黑币 +70 收起 理由
admin + 70 回帖助人的奖励!

查看全部评分

ID:158375 发表于 2019-2-20 13:45
楼主:设计不是想的那么简单,实现相同的功能,选用什么样的器件,很重要。
慢慢体会!
ID:475803 发表于 2019-2-19 20:47
wulin 发表于 2019-2-14 08:48
你的上述疑问是真实存在的,如果改用74HC595连级输出可以解决你的上述疑问。给你一个示例程序和仿真。

...

太感谢大神了!看的小弟我热泪盈眶
ID:213173 发表于 2019-2-14 08:48
izhonguo 发表于 2019-2-13 17:29
这两天又改了一下代码,现在可以正确按照顺序输出我自己定义的64bit的数组里面的0或者1,但是我有个疑问想 ...

你的上述疑问是真实存在的,如果改用74HC595连级输出可以解决你的上述疑问。给你一个示例程序和仿真。




#include <reg51.H>
#define uint unsigned int
#define uchar unsigned char
sbit        P_HC595_SER   = P0^0;
sbit        P_HC595_SRCLK = P0^1;
sbit        P_HC595_RCLK  = P0^2;

/*******************定义8个字节64 bit缓存数组*************************/
uchar data dis_buf[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//

/**************** 向HC595发送一个字节函数 ******************/
void Send_595(uchar dat)
{               
        uchar i;
        for(i=0;i<8;i++)
        {
                dat <<= 1;
                P_HC595_SER  = CY; //溢出位赋值数据输出端
                P_HC595_SRCLK = 1; //移位时钟
                P_HC595_SRCLK = 0;
        }
}
/**************** 向HC595发送八个字节函数 ******************/
void DisplayScan()
{       
        uchar j;
        for(j=0;j<8;j++)
        {
                Send_595(dis_buf[j]);//向HC595发送一个字节
        }
        P_HC595_RCLK = 1;//锁存输出数据
        P_HC595_RCLK = 0;
}

void main()
{
        P_HC595_SRCLK = 0;//初始化移位时钟端
        P_HC595_RCLK  = 0;//初始化锁存输出端
        DisplayScan();                //发送八个字节
        while(1);
}

ID:213173 发表于 2019-2-13 20:39
izhonguo 发表于 2019-2-13 15:36
总工程师您好,因为自己一直再改代码,所以最终放上去的一个和题目描述的不对,就是我现在需要处理一个64 ...

建议改用74HC595连级输出。ST_CP(12脚):上升沿时移位寄存器的数据进入数据存储寄存器,下降沿时存储寄存器数据不变。通常将ST_CP置为低电平,这样在移位过程中各输出端状态保持不变,当移位结束后,在ST_CP端产生一个正脉冲(5V时,大于几十纳秒就行了。通常都选微秒级),更新输出数据。
ID:475803 发表于 2019-2-13 15:40
yaoji123 发表于 2019-2-13 07:39
AT89C52的P0口在用时要加上拉电阻,否则电平不对

您好,请问P0的上拉电阻如何接线?是和51单片机的最小系统里的上拉电阻一样接法就可以吗?直接插一个10KΩ的电阻接地就可以吗?谢谢!
ID:432823 发表于 2019-2-13 07:39
AT89C52的P0口在用时要加上拉电阻,否则电平不对
ID:213173 发表于 2019-2-12 16:54
标题与内容描述不符,内容描述与程序不符,程序中数据类型定义与实际需要不符,看不明白楼主最终目的是什么。

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表