RS232接收的字节少于发送的

faunkyou 2010-08-12 09:20:05
我最近在做一个RS232的程序,遇到一个问题,就是我接收的数据有时候是对的,有时候是错的,比如我每次发送三个字节,但是接收的时候有的是只受到一个字节。
这是部分代码
 string ComportName = "COM1";
comPort = new SerialPort(ComportName, 14400, Parity.None, 8, StopBits.One);
comPort.ReadTimeout = 100;
comPort.WriteTimeout = 100;
comPort.DataReceived += ByteReceived;
//comPort.ReceivedBytesThreshold = 1;
// comPort.WriteBufferSize = 3;
comPort.Open();

这是接收事件:
 int byteToRead = comPort.BytesToRead;
byte[] resultByte = new byte[byteToRead];
comPort.Read(resultByte, 0, byteToRead);
...全文
615 44 打赏 收藏 转发到动态 举报
写回复
用AI写文章
44 条回复
切换为时间正序
请发表友善的回复…
发表回复
faunkyou 2011-03-02
  • 打赏
  • 举报
回复
怎么可能呢,串口发数据的长度是不确定的啊,肯定是你代码里限制了吧?[Quote=引用 43 楼 caoyuanshenju 的回复:]

我同样有个问题,我将电脑上串口的2和3号口短接,自发自收,但是发现只能收12帧数据,每帧8个字节,咋回事啊?????
[/Quote]
caoyuanshenju 2010-12-03
  • 打赏
  • 举报
回复
我同样有个问题,我将电脑上串口的2和3号口短接,自发自收,但是发现只能收12帧数据,每帧8个字节,咋回事啊?????
ztzname 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 23 楼 faunkyou 的回复:]

人身攻击。。。。
[/Quote]

偶自己灌水哦,说的我自己,
我每次发送完后会等带终端把字符全部返回了再进行接收,要不收不完全的,这个时间是多少自己可以测试,好友用循环判断字符串尾端,比如03这个报尾,证明全部收完,就可以以习性全部读出了。个人意见
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 39 楼 jsmouse 的回复:]

C# code


while (buffer.Count >= 12)
{
byte CRCH, CRCL; //这个是我CRC校验用的,
byte[] crcTemp = new byte[10];
b……
[/Quote]还在看代码。
jsmouse 2010-08-13
  • 打赏
  • 举报
回复


while (buffer.Count >= 12)
{
byte CRCH, CRCL; //这个是我CRC校验用的,
byte[] crcTemp = new byte[10];
buffer.CopyTo(0, crcTemp, 0, 10);

CRCData.CalculateCrc16(crcTemp, out CRCH, out CRCL);//一直到这 这个是我CRC校验用的,

if (buffer[10] != CRCH && buffer[11] != CRCL)//如果CRC校验不对,做下面的处理
{
buffer.RemoveAt(0);//删除BUFF中的第一个数据。
continue;//继续下一次循环
}


清楚没?
兔子-顾问 2010-08-13
  • 打赏
  • 举报
回复
二进制解析那篇中有缓存和数据分析
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 35 楼 xiemeilin 的回复:]

不要直接用sleep(1000)这样会让人感觉程序假死在那里,什么都动不了。
C# code
//系统延时
public void Delay(int ys)
{
for (int i = 1; i <= ys; i++)
{
//使用sleep(1)会比sleep……
[/Quote]关键是1s也不一定够用呀。
兔子-顾问 2010-08-13
  • 打赏
  • 举报
回复
二进制解析那篇中有缓存和数据分析
xiemeilin 2010-08-13
  • 打赏
  • 举报
回复
不要直接用sleep(1000)这样会让人感觉程序假死在那里,什么都动不了。
        //系统延时
public void Delay(int ys)
{
for (int i = 1; i <= ys; i++)
{
//使用sleep(1)会比sleep(1000)好,因为让进程循环1000休息1ms=1s比直接让系统休眠1s好
//如果直接让进程休眠1s,让人感觉进程好像卡了,反应很慢。
System.Threading.Thread.Sleep(1);
Application.DoEvents();
}
}
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 33 楼 xiemeilin 的回复:]

通信需要一定的延时的,不可能是不停的发不停的收,不然到时候会爆掉的,我觉得500ms或者1000ms都是可以的。
[/Quote]我发现如果是发过来100个字节的话,Sleep(100)就可以了,但是如果发送过来的字节数大于100,这样还是会丢失一些字节的。假如我Sleep(1000)那就是1S钟呀,影响效率,而且也不能从根本上解决问题呀,如果发送来的数据是成千上万,那不还是丢失吗?
xiemeilin 2010-08-13
  • 打赏
  • 举报
回复
通信需要一定的延时的,不可能是不停的发不停的收,不然到时候会爆掉的,我觉得500ms或者1000ms都是可以的。
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 wuyazhe 的回复:]

你数据缓存过没有?
[/Quote]前辈,请问我该怎么缓存呢?14楼那哥们儿的代码不完整,我没看明白。
andybang1981 2010-08-13
  • 打赏
  • 举报
回复
学习~~~~
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 29 楼 wuyazhe 的回复:]

你数据缓存过没有?
[/Quote]没有,我就直接读取需要读的字节数,然后直接comPort.Read(resultByte, 0, intByteToRead);
兔子-顾问 2010-08-13
  • 打赏
  • 举报
回复
你数据缓存过没有?
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 jsmouse 的回复:]

加一个死循环,
C# code

private void SerialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)//Getting data from Comm Port
{

try
……
[/Quote]请问代码里的CRCDATA是什么呀?
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 sp1234 的回复:]

只是注意#5楼的意见就足够了。当你说“我又调到最高”的时候,就完全暴露出问题来了。波特率、数据位、停止位等参数不是胡乱去调,而是必须双方一致。
[/Quote]我两端确实设置的是一致的,把波特率设置到最高也只是我调试过程中的一个方法而已,我也知道那样是不能从本质上解决问题的。现在我的问题还是怎么能获取所有要读取的字节数。虽然Thread.sleep()方法可以,但是效率太低了,而且你不知道需要sleep多久。不知道您明白了我的问题没有。
faunkyou 2010-08-13
  • 打赏
  • 举报
回复
OK,搞定了,结贴给分。
苦苦挣扎中 2010-08-12
  • 打赏
  • 举报
回复
LZ应该是测试,发送什么就返回什么
夜空皓月 2010-08-12
  • 打赏
  • 举报
回复
你两端的COM设置是否相同?
接收的字节数为什么要与发送的字节数相同?这很奇怪。接收的字节数应该是看设备的设置返回给你什么信息,跟你发送的字节数又不一样。
加载更多回复(23)
GS7020B GPRS LED 显示屏控制卡用户手册 一、 技术指标和特点 1. 同时支持GPRS 和串口通信。 2. GPRS 通信 (1) 频段:EGSM900/DCS1800 双频。 (2) 灵敏度: -106dBm (3) 最大发射功率: EGSM900 Class4(2W) DCS1800 Class1(1W) 3. 串口通信速率: 115200bps。 4. 单色控制范围: 32768 点(127 条节目)32*1024、64*512、128*256… 40960 点(31 条节目)48*832、64*640… 5. 支持扫描方式: 1/16、1/8、1/4、静态等。 6. 支持最多8 个分区。 7. 支持每日8 个时段的8 级亮度调节(含自动开关显示屏)。 8. 支持多种节目显示方式,可单独控制进入和退出方式。 9. 可定义节目的每日播放时段(最多4 个)。 10. 可定义节目播放的起始和终止日期。 11. 树形显示屏管理。支持快速节目群发。 12. 节目预览功能。 13. 发送失败后的自动重发功能。 14. 发送日志记录与查询。 15. 数字时钟(支持农历)、倒计时功能。 16. 支持动态域名解析。 17. 控制卡自带4 个12 接口和2 个08 接口。 18. 支持开关量输入报警功能(选项) 19. 多个显示屏节目同步播放(选项) 20. 操作方便的操作软件。 21. 供电电压: 5V 22. 工作温度: -40℃~+80℃ 二、 GS7020B 硬件 1. 控制卡布局: (1) RS232 及报警输入接口(9 芯针座) (2) 天线接口(阴头) (3) SIM 卡座 (4) 电源端子 (5) 显示屏扫描接口,6 个接口上排从左至右为 P2_12, P1_12, P1_08; 下排从左至右为 P4_12, P3_12, P3_08。 (6) OE 极性选择跳线 OE_SEL。应与显示单元板和控制卡软件软件配置一 致。 (7) 状态指示灯 (8) 时钟电池(3V 锂纽扣电池CR1220) 2. RS232 及报警输入接口信号定义: 1 – 报警开关量输入 2 – RXD 3 – TXD 4 – 空 5 – GND 6 – 空 7 – 空 8 – 空 9 – 空 3. OE 极性选择:  如果显示单元板OE 为低电平有效,除在软件配置中选择OE 反向外, 1 2 7 8 3 4 5 6 OE_SEL 应用跳线块短接右侧(-)的两个插针。如此可保证控制卡加 电期间显示屏为关闭状态而不会有亮线出现,从而减少对电源的冲击 并对控制卡的正常启动提供保障。  如果显示单元板OE 为高电平有效,除在软件配置中不选择OE 反向外, OE_SEL 应用跳线块短接左侧(+)的两个插针。如此可保证控制卡加 电期间显示屏为关闭状态而不会有亮线出现,从而减少对电源的冲击 并对控制卡的正常启动提供保障。 三、 使用前的准备工作 1. 电源 GS7020B 采用5V 电源供电,可与显示屏共用一个电源。由于 GPRS 通信 对电源要求较高,峰值最大可能需要电源能瞬间提供2A 电流并且电压跌 落不大于0.5V,因此应选用动态响应较好的电源。必要时可使用5V2A 的电源单独为GS7020B 供电。 如果GS7020B 与显示屏共用一个电源,应使用不超过1 米的电源线直接 从电源上引出,请勿使用经过若干显示单元板串接的电源。 注意:如果已经将显示单元板通过排线连接到了GS7020B,则一定要保 证显示屏单元板与GS7020B 同时供电或显示屏单元板先于GS7020B 供 电。否则可能造成GS7020B 接口驱动的损坏! 2. 手机卡和GPRS 资费 GS7020B 的GPRS 通信要求手机卡开通GPRS 数据业务。一般情况下需要 开通cmnet 来保证发送计算机通过Internet 与GS7020B 通信。客户可根 据自身情况选择中国移动或中国联通的GPRS 业务。 GS7020B 每个月最少需要10MB 流量,根据发送节目的平凡程度和节目 内容大小,客户可选择20~50MB 的包月流量。具体资费请咨询当地移动 运营商。 3. 串口通信 GS7020B 的RS232 串口可用来配置GPRS 通信参数或作为GPRS 通信的备 用通信方式。在正式使用GS7020B 前,用户可使用串口通信对 GS7020B 的显示和通信参数进行配置并可测试显示效果。 GS7020B 与计算机之间的串口线采用2-3 交叉的串口线通信。客户可以 自行制作或使用从市场上购买的标准交叉串口线。 4. 天线 GS7020B 标准配置为带3 米引线的磁性或无磁吸盘天线。使用时应将天 线置于手机信号较好的位置。除非显示屏位于信号较强的位置,一般应 将天线引出显示屏的金属外壳。 在露天环境中,要注意引出位置的防水 处理。 5. GPRS 通信服务器 GS7020B的GPRS 通信服务器可根据通信数据量的大小及服务器位置使用 一台单独的计算机或与发送软件共用一台计算机。 (1) 通信服务器的联网要求  通信服务器或其路由设备(路由器、交换机等)必须拥有 Internet 上的IP 地址(固定IP 或动态IP)。如果存在路由设备, 该路由设备客户应有修改其配置的权利和能力。  根据系统中显示屏的数量,具有相应的通信带宽 (2) 通信服务器常见构成方案: A. ADSL(中国联通、中国电信)路由器上网,路由器可获得动 态Internet IP 地址。 B. ADSL(中国联通、中国电信)路由器上网,并且路由器绑定 静态Internet IP 地址。 C. 计算机直接通过ADSL 拨号上网,可获得动态Internet IP 地 址。 D. 计算机直接通过ADSL 拨号上网,并且绑定静态Internet IP 地址。 E. 由Internet 网络接入商提供光纤、DDN 专线、等接入方式, 并提供Internet 固定IP 地址。 F. 由网络服务商托管服务器,服务器拥有Internet 固定IP 地址。 客户计算机可通过互联网访问该服务器。 (3) 服务器域名解析:  无论服务器是否拥有固定的Internet IP 地址,客户都可采用相 应的域名绑定业务使GS7020B 可通过该域名注册到服务器上。 但为了减少域名解析带来的额外通信流量,建议拥有固定 Internet IP 地址的客户直接使用该IP 地址通信。  如果客户采用的动态Internet IP 地址方案,则需要在服务器上 安装和运行动态域名解析(DDNS)客户端软件。常见的动态 域名解析软件有“花生壳”等。客户可到其网站下载、注册、 运行该软件。  采用动态Internet IP 地址方案和动态域名解析时,如果服务器 刚开机或断线重新上网,则最长可能要等待5 分钟,GS7020B 才能注册到服务器上。 (4) 路由器配置: 很多客户的局域网上的计算机是通过一个共用的ADSL 路由器联 接到Internet 上的。此时需要对路由器进行配置。下面以一种路 由器为例说明路由器的配置方法:  路由器型号:D_Link DI-704UP  路由器在局域网上的IP 地址: 本例中为192.168.0.1  客户计算机(用作GPRS 通信服务器)IP 地址: 本例中为 192.168.0.17。 注意:客户计算机IP 地址应采用静态IP, 勿使用DHCP 动态获 得。否则路由器配置在客户计算机或路由器重启后将不能正 确地指向客户计算机。  配置步骤: a. 打开浏览器,输入路由器起始页面地址: b. 如果路由器配置页面需要密码进入请输入用户名密码(本 例中的路由器出厂默认用户名和密码为admin、admin。 c. 进入路由器配置页面后选择相应选项,找到虚拟服务器 (Virtual Server)项。如下: 其中: Name(名称)为自己起的一个名字 Private IP(本地IP 地址)填客户计算机的IP 地址 Protocol Type(协议类型)选UDP 或所有(Both) Private Port(本地端口号):3700 Public Port(外网端口号) :3700 填好相应内容后,按下应用/保存(Apply/Save)按钮,即可 生效。 四、 单用户版服务器软件IpTransfer 使用说明 1. 安装与运行 本软件无需安装。直接拷贝并运行IpTransfer.exe 即可 2. 软件界面 界面中的上半部分指示客户端软件(GS702BMan)的连接和通信状态。 RX、TX 分别表示IpTransfer 从GS7020BMan 接收和向GS7020BMan 发送 的数据字节数。在线DTU 数量统计当前可通信的控制卡数量。 界面中的下半部分指示GS7020B 控制卡的连接和通信状态。RX、TX 分 别表示IpTransfer 从该控制卡接收和向该控制卡发送的数据字节数。最后 登陆时间指明服务器最近一次收到GS7020B 控制卡发送的登陆报文或命 令响应的时间。正常情况下,该时间距离当前时间不超过30 秒钟。 3. 用户名和密码 为防止对显示屏的不安全访问。客户端软件GS7020BMan 通过IpTransfer 向GS7020B 控制卡发送数据或命令均须通过口令检查。第一次运行 IpTransfer 后,应选择“用户/编辑”菜单设置用户名和密码: 用户名最长11 个字符;密码最长15 个字符。 4. 控制卡在线状态 对已经在线的控制卡,如果超过2 分钟未接收到新的登陆报文或数据, 则IpTansfer 从列表中删除该控制卡。 五、 客户端软件GS7020BMan 使用说明 1. 安装与运行 本软件无需安装。可将GS7020BMan_V2.x.exe 拷贝到一个文件夹里并运 行即可。 运行GS7020BMan_V2.x.exe 后,在其所在的文件夹中,可能会自动生成 一些新的文件和文件夹: 其中:config.ini 保存控制卡配置和节目信息;config 文件夹保存控制卡列 表信息;log 文件夹保存节目发送日志;txstatus.txt 保存各控制卡最后的 节目发送状态(是否成功)。 2. 软件升级和备份 如有新的GS7020BMan 软件版本,仅需将新软件拷贝到原来的安装目录 即可。 如果要更换计算机或进行备份。需要拷贝GS7020BMan 所在文件夹内的 所有内容,至少要备份config.ini 文件和config 文件夹。 3. 软件界面 菜单栏 工具条 显示屏列表 节目列表 节目内容 编辑区 节目属性 定义区 4. 通信配置 通信配置用于选择与控制卡的通信方式及定义有关参数。 选择菜单“系统/通信配置”项即可进入通信配置对话框。  串口通信方式主要用于修改控制卡内的GPRS 通信参数和本地测试, 也可用于安装运行后的GPRS 通信的备用通信方式及。  GPRS 通信服务器的IP 地址或域名是指运行IpTransfer 软件的计算机 的IP 地址或其域名。常见配置有以下几种情况: (1) GS7020BMan 和IpTransfer 运行在同一台计算机上,此时GPRS 通信服务器的IP 地址或域名应填写为”127.0.0.1”(IP 地址127.0.0.1 在计算机中表示本机)。 (2) GS7020BMan 和IpTransfer 运行在不同的计算机上,但两台计 算机处于同一个局域网中,此时GPRS 通信服务器的IP 地址或域 名应填写运行IpTransfer 的计算机的局域网IP 地址。 例: IpTransfer 运行在IP 地址为”192.168.0.17”的计算机上, GS7020BMan 运行在IP 地址为”192.168.0.220”的计算机上, 则此 处应填写”192.168.0.17”。 (3) GS7020BMan 和IpTransfer 运行在不同的计算机上,并且两台 计算机位于不同的局域网中。此时应填写运行IpTransfer 的计算 机所在网络的Internet IP 地址或域名。 例1:IpTransfer 运行的计算机上安装有动态域名解析软件,其域 名为”yuepoch.5166.info”, 则在GS7020BMan 中的GPRS 通信服务 器的IP 地址或域名应填写”yuepoch.5166.info” 例2:IpTransfer 运行在域名为”dtu.yuepoch.com”的计算机上, 且 该计算机拥有Internet 固定IP 地址”219.234.88.231”,则在 GS7020BMan 中的GPRS 通信服务器的IP 地址或域名应填写” dtu.yuepoch.com”或”219.234.88.231”。  用户名和密码此处要填写已在IpTransfer 中设定的用户名和密码。  GPRS 通信的超时时间和重试次数一般用4 秒和5 次。根据客户自身 的网络情况可适当改变,但由于GPRS 通信的特点,超时时间一般应 在3~15 秒之间。  自动重发间隔是指如果发送节目失败,则在失败后的指定时间后开始 尝试重新发送,如失败则再次等待指定时间发送,直至发送成功。如 此处为0,表示发送失败后不自动重发。不管此处是否指定了自动重 发时间间隔,用户随时都可手动开始重发未成功发送的节目内容。 5. 控制卡配置 在将控制卡连接到显示屏之前,应检查和修改控制卡中的有关配置。该 项也用于检查和修改控制卡内的GPRS 通信参数。在运行中也可远程修改 某些参数。 选择菜单“系统/控制卡配置”项或 按钮即可进入控制卡配置对话框。  设备编码:标识控制卡的最长11 个字符的字串。设备编码用于GPRS 通信。在一个系统中,不能有重复的编号。GS7020B 在出厂时已经预 写入唯一的设备编号,并已在控制卡标签上注明。在串口通信方式下, 该项可被修改,因此建议在修改配置前先读取控制卡配置,以防写入 错误的编号。GPRS 通信方式下,该项不可编辑修改。  GPRS APN: APN 是GPRS 接入点名称。除非在中国大陆以外运行 GS7020B, 或已从移动服务商获得专用的APN, 该项都应为”cmnet”。  服务器 IP 地址或域名: 是指运行IpTransfer 软件的计算机的Internet IP 地址或其域名。GS7020B 将在连接到GPRS 网络后向该项指定的计 算机定时发送登陆报文。  DNS 服务器1 和DNS 服务器2:域名解析服务器。目前GS7020B 依靠 自动获得的域名服务器解析GPRS 通信服务器域名,这两项暂时无用。  自动亮度调节:可设定每天8 个时段的8 级亮度(关屏-最亮)。  显示屏宽度、高度:按显示屏实际尺寸配置。  扫描方式: (1) 1/16(A) 32 点高1/16 扫描单元板 (2) 1/8(A) 16 点高1/8 扫描单元板 (3) 1/4(A) 16 点高1/4 扫描12 接口单元板(P10、P12.5…) (4) 1/4(B) 8 点高1/4 扫描12 接口单元板(P10…) (5) 1/16(B) 16 点高1/16 扫描08 接口单元板 (6) 1/16(C) 32 点高1/16 扫描08 接口单元板仅显示中间16 点 (7) 1/1(A) 静态显示单元板 (8) 1/1(B) 静态显示单元板  OE 反相: 显示单元板OE 低电平有效时选择该项。注意控制卡上的 OE_SEL 跳线应和此处设置一致,否则有可能造成开机失败。  数据反相:显示屏单元板数据低电平有效时选择该项。  扫描逆序:显示屏单元板上的ABCD 地址线反过来使用时选择该项。  字节逆序:暂不支持  折行输出:用于输出接口不够用时用Z 字形方式驱动显示屏。具体接 线与显示屏有关,具体使用请联系我公司技术支持。  双色:2.4 版本以下暂不支持。如驱动双色显示屏,请联系我公司技 术支持。  允许开关量报警:如选择该项,则在将控制卡上的9 针插座的1 脚和 5 脚短路200 毫秒后,将在显示屏上闪烁显示最后一个编号(127 或31) 的节目内容。一旦显示了报警内容,只有停止控制卡电源才能使其恢 复显示正常的节目内容。如未选择该项,最后一个编号(127 或31)的 节目将作为正常节目参与循环播放。  分区管理:GS7020B 支持最多8 各分区同时显示独立的节目内容。分 区位置坐标以显示屏左上角水平位置x = 0, 垂直位置y=0。每条节目 编辑时可指定其所属分区编号。为了方便操作,一般将需要经常编辑 节目内容的编号设为1。不经常改动的分区节目,例如时钟或倒计时 节目可使用编号较大的节目序号。 修改分区时可从分区管理下部的窗口中观察分区在显示屏上的位置 以检查分区设置是否正确。 6. 控制卡(显示屏)管理 GS7020BMan 采用树形分级显示屏管理。 选择菜单“系统/显示屏管理”项或 按钮即可进入显示屏管理对话框。 工具栏按钮自左至右分别为:添加显示屏组、添加显示屏、删除、重新 打开(恢复)之前保存的显示屏列表、保存。  修改显示屏组或显示屏名称:选中要编辑的项,在其名称上单击鼠标 左键,等待改名称变为可编辑状态后再进行修改。  修改显示屏设备编号:选中要编辑的项,在原编号上单击鼠标左键, 等待其变为可编辑状态后再进行修改。  退出显示屏管理窗口前请保存已经进行的修改。如果为保存改动,退 出窗口时将出现如下提示: 此时可选择保存后退出(是)、不保存退出(否)或回到显示屏管理 窗口(取消)。 7. 节目内容的编辑  节目内容直接在节目内容编辑区内输入完成。  编辑区内的每个网格表示一个显示屏的大小,目的是为了可以直观 地了解显示内容的显示位置。  单击节目列表项或改变下拉列表 可选择 当前编辑的节目。  通过 可以选择该节目所属分区。  节目内容说明修改后将在节目列表中显示,以方便进行节目管理。  节目现有内容实际播放所需要的时间可在节目编辑区上面显示出 来: ,单击刷新播放时间按 钮或者打开新节目时将重新计算播放时间。 (1) 节目文字内容的编辑  字体:按下 按钮即可弹出字体选择对话框。  水平对齐:编辑区外左上的三个按钮 分别为左对 齐、水平居中、有对齐。当文字内容少于一个屏宽时可用于 调整文字内容的水平位置。  垂直居中:当文字内容少于一个屏高时,按钮 可以调整 文字内容的垂直位置。  键盘命令 箭头键( ):移动编辑光标 回退键(Backspace):删除光标前的文字 删除键(Delete): 删除当前光标处的文字 Shift+箭头键( ):选择文字 Ctrl+C: 复制 Ctrl+V:粘贴 Ctrl+X: 剪切 Ctrl+A:选择所有文字  可以使用鼠标改变光标位置(单击左键)和选择文字(按下 左键拖动)。  在编辑区内单击鼠标右键,可弹出编辑命令菜单。 (2) 节目图片内容的编辑  按下 按钮即可弹出图片文件选择对话框。  GS7020BMan 仅支持bmp 格式的文件,并将彩色文件转换为 单色格式显示。  通过调整 ,可以改变图片的位置。  图片的大小可以超过显示屏的显示范围。  每个节目只能加载一个图片。 (3) 节目内容的删除。 除了可以使用键盘命令和右键菜单删除节目文字内容外,还可以 通过编辑菜单中相应命令删除全部文字、图片内容。  注意使用这些菜单命令前,要确认节目列表中的选择框是否 正确。 8. 节目显示属性控制  节目进入方式  直接显示:立即显示一个屏幕的内容。如果节目内容超过一 个屏幕,则按先从左到右再从上到下的次序分多次载入显示 内容。该显示方式下,应注意文字不要跨在屏幕分割线上。  连续左移:第1 个屏高的节目内容全部向左连续移入  连续右移:第1 个屏高的节目内容全部向右连续移入  连续上移:第1 个屏宽的节目内容全部向上连续移入  连续下移:第1 个屏宽的节目内容全部向下连续移入  向左移入:第1 个屏高的节目内容向左移入屏幕,如果节目 宽度超过一个屏幕,则按从左到右的次序分多次移入。  向右移入:第1 个屏高的节目内容向左移入屏幕,如果节目 宽度超过一个屏幕,则按从右到左的次序分多次移入。  向上移入:第1 个屏宽的节目内容向上移入屏幕,如果节目 高度超过一个屏幕,则按从上到下的次序分多次移入。  向下移入:第1 个屏宽的节目内容向下移入屏幕,如果节目 高度超过一个屏幕,则按从下到上的次序分多次移入。  向右展开:  向左展开:  向下展开:  向上展开:  从左右向中间展开:  从中间向左右展开:  从上下向中间展开:  从中间向上下展开:  水平百叶窗:  垂直百叶窗: 显示一个屏幕的内容。如果节目内容超过一个屏幕,则按先 从左到右再从上到下的次序分多次载入显示内容。在这些显 示方式下,应注意文字不要跨在屏幕分割线上。 百叶窗的页片宽度可定义,一般取8~64  节目退出方式:  直接清除:  向左移出:  向右移出:  向上移出:  向下移出:  向右擦除:  向左擦除:  向下擦除:  向上擦除:  从左右向中间擦除:  从中间向左右擦除:  从上下向中间擦除:  从中间向上下擦除:  水平百叶窗:  垂直百叶窗:  无:不退出。根据本节目的下一部分内容或下一条节目内容 的进入方式决定显示方式。  进入速度和退出速度: 单位为毫秒。指每做一次动作,例如左移一个像素宽度所需要的 时间。直接显示和直接清除方式对应的进入速度和退出速度无 效。该数值越大,动作速度越慢。 一般取值再16~50 之间。 对1/16 扫描的16 点高显示屏,取值16 可获得平滑清晰的左移和 右移效果。  停留时间: 单位为毫秒。指一次进入方式动作完成后,显示内容在屏幕上静 止停留的时间。  起始时间和终止时间: 节目在该项指定的时间范围内才会被播放。  每日播放时段 节目在该项指定的时段范围内才会被播放。 上图中第一个时段为0 时0 分至23 时59 分(含59 分),即全天 播放。后三个时段起始时间和终止时间相同,表示无效。 如果已经播放了部分内容,即使此时终止时间到,该节目也会被 继续播放完成。 9. 节目显示效果预览  可以通过菜单“编辑/预览当前编辑的节目”项在电脑显示屏上预览 当前编辑的节目的显示效果。要停止预览,选择菜单“编辑/停止预 览当前编辑的节目”。  可以通过菜单“编辑/预览所有节目”项或 按钮在电脑显示屏上 预览总的显示效果。要停止预览,选择菜单“编辑/停止预览所有节 目”。 10. 数字时钟和倒计时 数字时钟和倒计时项统称为动态变化项。含有动态变化项的节目的进入 方式只能选择“直接显示”, 退出方式可以选“直接清除”或“无”,停留 时间选1000 毫秒以上。 例如要显示格式为 “2010 年11 月17 日 23:31:31 星期三”的数字时钟。  步骤1:先输入以上文字(具体的年、月、日、时、分、秒、星期等 数值随意)。  步骤2:选中2010 四个数字,再选择菜单“编辑/将所选文字设为动 态变化项”。等弹出如下对话框后,选择动态类型为“4 位数字年”, 点确定即可。 此时2010 四个数字将变成暗红色显示 :  步骤3:选中11 两个数字,再选择菜单“编辑/将所选文字设为动态 变化项”。 在设定动态文字对话框中选择动态类型为“2 位数字月”, 确定。  步骤4:依次选择动态类型,最后输入文字效果如下:  步骤5:设定显示方式等: 11. 节目的导出和导入 某些节目具有一定的代表性,此时可以选择菜单“编辑/导出当前节目” 将该节目导出至某一个节目文件。在编辑其它类似节目时可以选择菜单 “编辑/从节目文件导入到当前节目”来导入保存好的节目内容,然后在 此基础上修改即可。 12. 发送节目内容  发送节目内容的步骤: (1) 选择要进行操作的显示屏 (2) 选择要发送的节目 (3) 选择菜单“通信/发送节目内容”或 按钮即可开始发送 (4) 发送状态和是否成功可在相应的显示屏控制卡的通信状态/ 结果栏中观察到。  发送节目中如果出现单次命令响应失败,将按照通信配置中设置的次 数尝试重新发送该命令。  如果向某个显示屏发送节目失败,可以选择菜单“通信/查看所选显 示屏未成功发送的节目”以在所选显示屏通信状态/结果栏中显示未 成功发送的节目列表。  选择菜单“通信/重新发送上次未成功发送的节目内容”,可以手动发 起重新补发未成功发送的节目。  如果在通信配置中选择了自动重发,则在发送失败后的指定时间后将 弹出如下提示,并在未被手动推迟的情况下自动发起重新发送。 13. 查询控制卡在线状态 选择菜单“通信/查询控制卡在线状态”或 按钮即可查询所选择 控制卡的在线状态。如果该控制卡在线,则对应通信状态/结果栏中 将显示“在线”,否则显示“-”。 14. 查询控制卡时钟 选择菜单“通信/查询控制卡时钟”或 按钮即可查询所选择控制 卡的当前时钟。通信结果显示在其对应的通信状态/结果栏中。 15. 校对控制卡时钟 选择菜单“通信/校对控制卡时钟”或 按钮即可用发送计算机的 时钟校对所选择的控制卡。通信结果显示在其对应的通信状态/结果 栏中。 16. 开关量输入报警  如果要使用报警功能,在控制卡配置中应选择“允许开关量报警”并 写入控制卡。  报警输入为9 针D 型插座的1 脚和5 脚。如果这两个引脚连续短路 0.2 秒以上,则可引发报警显示。  报警显示的内容在控制卡允许的最后一条节目(第127 条或第31 条) 中定义。  报警显示内容节目的进入方式应选择“直接显示”,退出方式可选择 “无”,停留时间一般选300 毫秒。实际显示时,将以快闪方式显示。  报警显示一旦启动,则只有断开控制卡电源才能取消。  如果在控制卡配置中为选择“允许开关量报警”,则控制卡允许的最 后一条节目(第127 条或第31 条)将作为普通节目参与循环播放。 17. 查看发送日志 选择菜单“日志/查看节目发送记录”可打开如下记录窗口:
文库帮手网 www.365xueyuan.com 免费帮下载 百度文库积分 资料 本文由pengliuhua2005贡献 doc文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 51 单片机设计跑马灯的程序用(c 语言)编写 P1 口接 8 个发光二极管共阳,烧入下面程序 #include unsigned char i; unsigned char temp; unsigned char a,b; void delay(void) { unsigned char m,n,s; for(m=20;m>0;m--) for(n=20;n>0;n--) for(s=248;s>0;s--); } void main(void) { while(1) { temp=0xfe; P1=temp; delay(); for(i=1;i<8;i++) { a=temp(8-i); P1=a|b; delay(); } for(i=1;i>i; b=temp<= 4000 ){ us250 = 0; if( ++s1 >= 10 ){ s1 = 0; if( ++s10 >= 6 ) s10 = 0; if( key10 == 1 ){ //等松键 if( P3.2 == 1 ) key10=0; } //未按键 37. else{ 38. 39. 40. 41. if( P3.2 == 0 ){ key10 = 1; if( ++s10 >= 6 ) s10 = 0; break; //结束“循环 2”,修改显示 42. 43. 44. 45. 46. } } //按个位键处理 P3.3 = 1; //P3.3 作为输入,先要输出高电平 if( key1 == 1 ) //等松键 47. { if( P3.3 == 1 ) key1=0; } 48. 49. 50. 51. 52. 53. 54. 55. } } //循环 2’end }//循环 1’end } else { //未按键 if( P3.3 == 0 ){ key1 = 1; if( ++s1 >= 10 ) s1 = 0; break; //结束“循环 2”,修改显示 56. }//main’end 第三节: 第三节:十字路口交通灯 如果一个单位时间为 1 秒,这里设定的十字路口交通灯按如下方式四个步骤循环工作: 60 个单位时间,南北红,东西绿;λ 10 个单位时间,南北红,东西黄;λ 60 个单位时间,南北绿,东西红;λ 10 个单位时间,南北黄,东西红;λ 解:用 P1 端口的 6 个引脚控制交通灯,高电平灯亮,低电平灯灭。 代码 1. 2. 3. 4. 5. 6. 7. 8. 9. #include //sbit 用来定义一个符号位地址,方便编程,提高可读性,和可移植性 sbit SNRed =P1^0; //南北方向红灯 //南北方向黄灯 //南北方向绿灯 //东西方向红灯 //东西方向黄灯 //东西方向绿灯 sbit SNYellow =P1^1; sbit SNGreen =P1^2; sbit EWRed =P1^3; sbit EWYellow =P1^4; sbit EWGreen =P1^5; /* 用软件产生延时一个单位时间 */ 10. void Delay1Unit( void ) 11. { 12. 13. 14. unsigned int i, j; for( i=0; i<1000; i++ ) for( j<0; j= 8 ) i=0; 12. } 13. void Timer0IntRoute( void ) interrupt 1 14. { 15. 16. TL0 = -1000; //由于 TL0 只有 8bits,所以将(-1000)低 8 位赋给 TL0 TH0 = (-1000)>>8; //取(-1000)的高 8 位赋给 TH0,重新定时 1ms 17. 18. } DisplayBrush(); 19. void Timer0Init( void ) 20. { TMOD=(TMOD & 0xf0) | 0x01; //初始化,定时器 T0,工作方式 1 21. 22. 23. 24. 25. } 26. void Display( unsigned char index, unsigned char dataValue ){ DisBuf[ inde x ] = dataValue; } 27. void main( void ) 28. { 29. unsigned char i; 30. for( i=0; i>8; TR0 = 1; ET0 = 1; //允许 T0 开始计数 //允许 T0 计数溢出时产生中断请求 第五节:键盘驱动 第五节: 指提供一些函数给任务调用,获取按键信息,或读取按键值。 定义一个头文档 ,描述可用函数,如下: 代码 1. 2. 3. 4. 5. 6. 7. #ifndef _KEY_H_ #define _KEY_H_ //防止重复引用该文档,如果没有定义过符号 _KEY_H_,则编译下面语句 防止重复引用该文档, , 防止重复引用该文档 //只要引用过一次,即 #include ,则定义符号 _KEY_H_ 只要引用过一次, 只要引用过一次 , unsigned char keyHit( void ); //如果按键,则返回非0,否则返回0 unsigned char keyGet( void ); //读取按键值,如果没有按键则等待到按键为止 void keyPut( unsigned char ucKeyVal ); //保存按键值 ucKeyVal 到按键缓冲队列末 void keyBack( unsigned char ucKeyVal ); //退回键值 ucKeyVal 到按键缓冲队列首 #endif 定义函数体文档 KEY.C,如下: 代码 1. 2. 3. #include “key.h” #define KeyBufSize 16 //定义按键缓冲队列字节数 定义按键缓冲队列字节数 unsigned char KeyBuf[ KeyBufSize ]; //定义一个无符号字符数组作为按键缓冲队列。该队列为 先进 4. 5. 6. 7. 8. 9. 10. //先出,循环存取,下标从0到 KeyBufSize-1 unsigned char KeyBufWp=0; //作为数组下标变量,记录存入位置 unsigned char KeyBufRp=0; //作为数组下标变量,记录读出位置 //如果存入位置与读出位置相同,则表明队列中无按键数据 unsigned char keyHit( void ) { if( KeyBufWp == KeyBufRp ) return( 0 ); else return( 1 ); } 11. unsigned char keyGet( void ) 12. { unsigned char retVal; //暂存读出键值 13. while( keyHit()==0 ); //等待按键,因为函数 keyHit()的返回值为 0 表示无按键 14. retVal = KeyBuf[ KeyBufRp ]; //从数组中读出键值 15. if( ++KeyBufRp >= KeyBufSize ) KeyBufRp=0; //读位置加1, 超出队列则循环回初始位置 16. 17. } 18. 19. void keyPut( unsigned char ucKeyVal ) 20. { KeyBuf[ KeyBufWp ] = ucKeyVal; //键值存入数组 21. if( ++KeyBufWp >= KeyBufSize ) KeyBufWp=0; //存入位置加1, 超出队列则循环回初始位置 return( retVal ); 22. } 23. 由于某种原因,读出的按键,没有用,但其它任务要用该按键,但传送又不方便。此时可以退回按键队列。 就如取错了信件,有必要退回一样 24. void keyBack( unsigned char ucKeyVal ) 25. { 26. 27. 如果 KeyBufRp=0; 减 1 后则为 FFH,大于 KeyBufSize,即从数组头退回到数组尾。或者由于干扰使得 KeyBufRp 超出队列位置,也要调整回到正常位置, 28. */ 29. if( --KeyBufRp >= KeyBufSize ) KeyBufRp=KeyBufSize-1; 30. KeyBuf[ KeyBufRp ] = ucKeyVal; //回存键值 31. } 下面渐进讲解键盘物理层的驱动。 电路共同点:P2 端口接一共阴数码管,共阴极接 GND,P2.0 接 a 段、P2.1 接 b 段、…、P2.7 接 h 段。 软件共同点:code unsigned char Seg7Code[10] 是七段数码管共阴编码表。 Code unsigned char Seg7Code[16]= // 0 1 2 3 4 5 6 7 8 9 A b C d E F {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71}; 例一:P1.0 接一按键到 GND,键编号为‘6’,显示按键。 代码 1. 2. 3. 4. 5. 6. 7. 8. 9. #include #include “KEY.H” void main( void ) { P1_0 = 1; //作为输入引脚,必须先输出高电平 while( 1 ) //永远为真,即死循环 { if( P1_0 == 0 ) //如果按键,则为低电平 { keyPut( 6 ); //保存按键编号值为按键队列 while( P1_0 == 0 ); //如果一直按着键,则不停地执行该循环,实际是等待松键 } 10. if( keyHit() != 0 ) //如果队列中有按键 11. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 12. 13. } } 例二:在例一中考虑按键 20ms 抖动问题。 代码 1. 2. 3. 4. 5. 6. 7. 8. 9. #include #include “KEY.H” void main( void ) { P1_0 = 1; //作为输入引脚,必须先输出高电平 while( 1 ) //永远为真,即死循环 { if( P1_0 == 0 ) //如果按键,则为低电平 { delay20ms(); //延时 20ms,跳过接下抖动 keyPut( 6 ); //保存按键编号值为按键队列 while( P1_0 == 0 ); //如果一直按着键,则不停地执行该循环,实际是等待松键 10. delay20ms(); //延时 20ms,跳过松开抖动 11. } 12. if( keyHit() != 0 ) //如果队列中有按键 13. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 14. 15. } } 例三:在例二中考虑干扰问题。即小于 20ms 的负脉冲干扰。 代码 1. 2. 3. 4. 5. 6. #include #include “KEY.H” void main( void ) { P1_0 = 1; //作为输入引脚,必须先输出高电平 while( 1 ) //永远为真,即死循环 { if( P1_0 == 0 ) //如果按键,则为低电平 7. 8. 9. 10. { delay20ms(); //延时 20ms,跳过接下抖动 if( P1_0 == 1 ) continue; //假按键 keyPut( 6 ); //保存按键编号值为按键队列 while( P1_0 == 0 ); //如果一直按着键,则不停地执行该循环,实际是等待松键 11. delay20ms(); //延时 20ms,跳过松开抖动 12. } 13. if( keyHit() != 0 ) //如果队列中有按键 14. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 15. 16. } } 例四:状态图编程法。通过 20ms 周期中断,扫描按键。 代码 采用晶体为 12KHz 时,指令周期为 1ms(即主频为 1KHz),这样 T0 工作在定时器方式 2,8 位自动重载。 计数值为 20,即可产生 20ms 的周期性中断,在中断服务程序中实现按键扫描 2. 3. 4. 5. 6. 7. 8. 9. #include #include “KEY.H” void main( void ) { TMOD = (TMOD & 0xf0 ) | 0x02; //不改变 T1 的工作方式,T0 为定时器方式 2 TH0 = -20; TL0=TH0; TR0=1; //计数周期为 20 个主频脉,即 20ms //先软加载一次计数值 //允许 T0 开始计数 //允许 T0 计数溢出时产生中断请求 //允许 CPU 响应中断请求 1. 10. ET0=1; 11. EA=1; 12. while( 1 ) //永远为真,即死循环 13. { 14. if( keyHit() != 0 ) //如果队列中有按键 15. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 16. 17. } 18. void timer0int( void ) interrupt 1 //20ms;T0 的中断号为 1 19. { static unsigned char sts=0; 20. P1_0 = 1; //作为输入引脚,必须先输出高电平 } 21. switch( sts ) 22. 23. 24. { case 0: if( P1_0==0 ) sts=1; break; //按键则转入状态 1 case 1: //假按错,或干扰,回状态 0 25. if( P1_0==1 ) sts=0; 26. else{ sts=2; keyPut( 6 ); } //确实按键,键值入队列,并转状态 2 27. break; 28. case 2: if( P1_0==1 ) sts=3; break; //如果松键,则转状态 3 29. 30. 31. 32. 33. } } case 3: if( P1_0==0 ) sts=2; else sts=0; //假松键,回状态 2 //真松键,回状态 0,等待下一次按键过程 例五:状态图编程法。 代码 如果采用晶体为 12MHz 时,指令周期为 1us(即主频为 1MHz),要产生 20ms 左右的计时,则计数值达到 20000,T0 工作必须为定时器方式 1,16 位非自动重载,即可产生 20ms 的周期性中断,在中断服务程序中 实现按键扫描 2. 3. 4. 5. 6. 7. 8. 9. #include #include “KEY.H” void main( void ) { TMOD = (TMOD & 0xf0 ) | 0x01; //不改变 T1 的工作方式,T0 为定时器方式 1 TL0 = -20000; TH0 = (-20000)>>8; TR0=1; //计数周期为 20000 个主频脉,自动取低 8 位 //右移 8 位,实际上是取高 8 位 1. //允许 T0 开始计数 //允许 T0 计数溢出时产生中断请求 //允许 CPU 响应中断请求 10. ET0=1; 11. EA=1; 12. while( 1 ) //永远为真,即死循环 13. { 14. if( keyHit() != 0 ) //如果队列中有按键 15. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 16. 17. } 18. void timer0int( void ) interrupt 1 //20ms;T0 的中断号为 1 19. { static unsigned char sts=0; 20. TL0 = -20000; 21. TH0 = (-20000)>>8; 22. P1_0 = 1; //方式 1 为软件重载 //右移 8 位,实际上是取高 8 位 } //作为输入引脚,必须先输出高电平 23. switch( sts ) 24. 25. 26. { case 0: if( P1_0==0 ) sts=1; break; //按键则转入状态 1 case 1: //假按错,或干扰,回状态 0 27. if( P1_0==1 ) sts=0; 28. else{ sts=2; keyPut( 6 ); } //确实按键,键值入队列,并转状态 2 29. break; 30. 31. 32. 33. case 2: if( P1_0==1 ) sts=3; break; //如果松键,则转状态 3 case 3: if( P1_0==0 ) sts=2; else sts=0; //假松键,回状态 2 //真松键,回状态 0,等待下一次按键过程 34. 35. } } 例六:4X4 按键。 代码 由 P1 端口的高 4 位和低 4 位构成 4X4 的矩阵键盘, 本程序只认为单键操作为合法, 同时按多键时无效。 这样下面的 X,Y 的合法值为 0x7, 0xb, 0xd, 0xe, 0xf,通过表 keyCode 影射变换可得按键值 1. 2. 3. 4. 5. 6. 7. 8. #include #include “KEY.H” unsigned char keyScan( void ) //返回 0 表示无按键,或无效按键,其它值为按键编码值 { code unsigned char keyCode[16]= /0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0 xF 9. { 0, }; 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 4, 0 10. unsigned char x, y, retVal; 11. P1=0x0f; 12. x=P1&0x0f; 13. P1=0xf0; //低四位输入,高四位输出 0 //P1 输入后,清高四位,作为 X 值 //高四位输入,低四位输出 0 14. y=(P1 >> 4) & 0x0f; //P1 输入后移位到低四位,并清高四位,作为 Y 值 15. retVal = keyCode[x]*4 + keyCode[y]; //根据本公式倒算按键编码 16. if( retVal==0 ) return(0); else return( retVal-4 ); 17. } 18. //比如按键‘1’,得 X=0x7,Y=0x7,算得 retVal= 5,所以返回函数值 1。 19. //双如按键‘7’,得 X=0xb,Y=0xd,算得 retVal=11,所以返回函数值 7。 20. void main( void ) 21. { 22. TMOD = (TMOD & 0xf0 ) | 0x01; //不改变 T1 的工作方式,T0 为定时器方式 1 23. TL0 = -20000; 24. TH0 = (-20000)>>8; 25. TR0=1; 26. ET0=1; 27. EA=1; //计数周期为 20000 个主频脉,自动取低 8 位 //右移 8 位,实际上是取高 8 位 //允许 T0 开始计数 //允许 T0 计数溢出时产生中断请求 //允许 CPU 响应中断请求 28. while( 1 ) //永远为真,即死循环 29. { 30. if( keyHit() != 0 ) //如果队列中有按键 31. P2=Seg7Code[ keyGet() ]; //从队列中取出按键值,并显示在数码管上 32. 33. } 34. void timer0int( void ) interrupt 1 //20ms;T0 的中断号为 1 } 35. { static unsigned char sts=0; 36. TL0 = -20000; 37. TH0 = (-20000)>>8; 38. P1_0 = 1; //方式 1 为软件重载 //右移 8 位,实际上是取高 8 位 //作为输入引脚,必须先输出高电平 39. switch( sts ) 40. 41. 42. { case 0: if( keyScan()!=0 ) sts=1; break; //按键则转入状态 1 case 1: //假按错,或干扰,回状态 0 43. if( keyScan()==0 ) sts=0; 44. else{ sts=2; keyPut( keyScan() ); } //确实按键,键值入队列,并转状态 2 45. break; 46. 47. 48. 49. 50. 51. } } case 2: if(keyScan()==0 ) sts=3; break; //如果松键,则转状态 3 case 3: if( keyScan()!=0 ) sts=2; else sts=0; //假松键,回状态 2 //真松键,回状态 0,等待下一次按键过程 第六节: 第六节:低频频率计 实例目的:学时定时器、计数器、中断应用 说明:选用 24MHz 的晶体,主频可达 2MHz。用 T1 产生 100us 的时标,T0 作信号脉冲计数器。假设 晶体频率没有误差,而且稳定不变(实际上可达万分之一);被测信号是周期性矩形波(正负脉冲宽 度都不能小于 0.5us),频率小于 1MHz,大于 1Hz。要求测量时标 1S,测量精度为 0.1%。 解:从测量精度要求来看,当频率超过 1KHz 时,可采用 1S 时标内计数信号脉冲个数来测量信号频, 而信号频率低于 1KHz 时,可以通过测量信号的周期来求出信号频率。两种方法自动转换。 对于低于 1KHz 的信号,信号周期最小为 1ms,也就是说超过 1000us,而我们用的定时器计时脉冲周 期为 0.5us,如果定时多计或少计一个脉冲,误差为 1us,所以相对误差为 1us/1000us=0.1%。信号 周期越大,即信号频率越低,相对误差就越小。 从上面描述来看,当信号频率超过 1KHz 后,信号周期就少于 1000us,显然采用上面的测量方法,不 能达到测量精度要求,这时我们采用 1S 单位时间计数信号的脉冲个数,最少能计到 1000 个脉冲,由 于信号频率不超过 1MHz,而我们定时脉冲为 2MHz,最差多计或少计一个信号脉冲,这样相对误差为 1/1000,可见信号频率越高,相对误差越小。 信号除输入到 T1(P3.5)外,还输入到 INT1(P3.3)。 代码 //对 100us 时间间隔单位计数,即有多少个 100us。 1. 2. 3. 4. 5. 6. 7. unsigned int us100; unsigned char Second; unsigned int K64; unsigned char oldT0; //对 64K 单位计数,即有多少个 64K unsigned int oldus, oldK64, oldT1; unsigned long fcy; bit HighLow=1; //存放频率值,单位为 Hz //1:表示信号超过 1KHz;0:表示信号低于 1KHz。 8. 9. 10. void InitialHigh( void ) { IE=0; IP=0; HighLow=1; 11. TMOD = (TMOD & 0xf0) | 0x02; TH0=-200; TL0=TH0; PX0=1; T0=1; 12. 13. 14. 15. 16. 17. } 18. void InitialLow( void ) 19. { 20. IE=0; IP=0; HighLow=0; TMOD = (TMOD & 0x0f) | 0x50; TH1=0; TL1=0; T1=1; ET1=1; Us100=0; Second=0; K64=0; oldK64=0; oldT1=0; TCON |= 0x50; EA = 1; //同时置 TR0=1; TR1=1; 同时置 21. TMOD = (TMOD & 0xf0) | 0x02; TH0=-200; TL0=TH0; ET0=1; TR0=1; 22. 23. 24. 25. 26. } 27. void T0intr( void ) interrupt 1 28. { if( HighLow==0 ) ++us100; 29. else 30. if( ++us100 >= 10000 ) 31. { unsigned int tmp1, tmp2; INT1 = 1; IT1=1; EX1=1; Us100=0; Second=0; K64=0; oldK64=0; oldT1=0; EA = 1; 32. TR1=0; tmp1=(TH1<<8) + (TL1); tmp2=K64; TR1=1; 33. fcy=((tmp2-oldK64)<<16) + (tmp1-oldT1); 34. oldK64=tmp1; oldT1=tmp2; 35. Second++; 36. us100=0; 37. } 38. } 39. void T1intr( void ) interrupt 3 { ++K64; } 40. void X1intr( void ) interrupt 2 41. { static unsigned char sts=0; 42. switch( sts ) 43. { 44. case 0: sts = 1; break; 45. case 1: oldT0=TL0; oldus=us100; sts=2; break; 46. case 2: 47. { 48. 49. 50. 51. 52. } 53. 54. 55. Sts = 0; break; } unsigned char tmp1, tmp2; TR0=0; tmp1=TL0; tmp2=us100; TR0=1; fcy = 1000000L/( (tmp2-oldus)*100L + (256-tmp1)/2 ); Second ++; 56. } 57. void main( void ) 58. { 59. if( HighLow==1) InitialHigh(); else InitialLow(); 60. 61. While(1) { 62. if( Second != 0 ) 63. { 64. Second = 0; 65. //display fcy 引用前面的数码管驱动程序, 引用前面的数码管驱动程序,注意下面对 T0 中断服务程序的修改 66. { unsigned char i; 67. 68. } 69. if( HighLow==1 ) 70. if( fcy1000L ){ InitalHigh();} for( i=0; i= 10000 ) 83. { unsigned int tmp1, tmp2; 84. TR1=0; tmp1=(TH1<<8) + (TL1); tmp2=K64; TR1=1; 85. fcy=((tmp2-oldK64)<= 10 ){ ms=0; DisplayBrush(); } //1ms 数码管刷新 第七节: 第七节:电子表 单键可调电子表:主要学习编程方法。 外部中断应用,中断嵌 解:电子表分为工作状态和调整状态。平时为工作状态,按键不足一秒,接键为换屏‘S’。按键超过一 秒移位则进入调整状态‘C’,而且调整光标在秒个位开始。调整状态时,按键不足一秒为光标移动‘M’, 超过一秒则为调整读数,每 0.5 秒加一‘A’,直到松键;如果 10 秒无按键则自动回到工作状态‘W’。 如果有年、月、日、时、分、秒。四联数码管可分三屏显示,显示格式为“年月.”、“日.时.”、“分.秒”, 从小数点的位置来区分显示内容。(月份的十位数也可以用“-”和“-1”表示)。 代码 1. 2. 3. enum status = { Work, Change, Add, Move, Screen } //状态牧举 //计时和调整都是对下面时间数组 Time 进行修改 unsigned char Time[12]={0,4, 0,6, 1,0, 0,8, 4,5, 3,2}; //04 年 06 月 10 日 08 时 45 分 32 秒 4. 5. 6. 7. unsigned char cursor = 12; //指向秒个位,=0 时无光标 unsigned char YmDhMs = 3; //指向“分秒”显示 ,=0 时无屏显 static unsigned char sts = Work; 如果 cursor 不为 0,装入 DisBuf 的对应数位,按 0.2 秒周期闪烁,即设一个 0.1 秒计数器 S01,S01 为奇数时灭,S01 为偶数时亮。 8. 9. 小数点显示与 YmDhMs 变量相关。 */ 10. void DisScan( void ) //动态刷新显示时调用。没编完,针对共阴数码管,只给出控控制算法 11. { 12. //DisBuf 每个显示数据的高四位为标志,最高位 D7 为负号,D6 为小数点,D5 为闪烁 13. unsigned char tmp; 14. 15. 16. 17. 18. 19. } 20. void Display( void ) 21. { 22. if( cursor != 0 ){ YmDhMs=(cursor+3)/4; } //1..4=1; 5..8=2; 9..12=3 //根据状态进行显示 tmp = Seg7Code[?x & 0x1f ]; //设?x 为显示数据,高 3 位为控制位,将低 5 位变为七段码 if( ?x & 0x40 ) tmp |= 0x80; //添加小数点 if( ?x & 0x20 ){ if( S01 & 0x01 ) tmp=0; } //闪烁,S01 奇数时不亮 //这里没有处理负号位 //将 tmp 送出显示,并控制对应数码管动作显示 23. for( i=(YmDhMs-1)*4; i ‘9’) Dat=‘0’; } 二、 在上题的基础上,改为 2400bps,循环发送小写字母‘a’到‘z’,然后是大写字母‘A’到‘Z’。 代码 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. #include void main( void ) { TMOD = (TMOD & 0x0F) | 0x20; TH1 = -96; //注意不用倍频方式 PCON &= 0x7F; //SMOD = 0 TR1 = 1; SCON = 0x42; while( 1 ) { if( TI==1 ) { static unsigned char Dat=‘a’; SBUF = Dat; TI = 0; //If( ++Dat > ‘9’) Dat=‘0’; ++Dat; if( Dat == (‘z’+1) ) if( Dat == (‘Z’+1) ) } } Dat=‘A’; Dat=‘a’; 22. } 上述改变值时,也可以再设一变量表示当前的大小写状态,比如写成如下方式: 代码 1. 2. 3. 4. ++Dat; { static unsigned char Caps=1; if( Caps != 0 ) 5. 6. 7. 8. } if( Dat>‘Z’){ Dat=‘a’; Caps=0; } else if( Dat>‘z’){ Dat=‘A’; Caps=1; } 如下写法有错误:因为小 b 比大 Z 的编码值大,所以 Dat 总是‘a’ 代码 1. 2. 3. ++Dat; if( Dat>‘Z’){ Dat=‘a’} else if( Dat>‘z’){ Dat=‘A’} 三、 有 A 和 B 两台单片机,晶体频率分别为 13MHz 和 14MHz,在容易编程的条件下,以最快的速度进 行双工串行通信,A 给 B 循环发送大写字母从‘A’到‘Z’,B 给 A 循环发送小写字母从‘a’到‘z’,双方都用 中断方式进行收发。 解:由于晶体频率不同,又不成 2 倍关系,所以只有通信方式 1 和方式 3,由于方式 3 的帧比方式 1 多一位,显然方式 3 的有效数据(9/11)比方式 1(8/10)高,但要用方式 3 的第 9 位 TB8 来发送数 据,编程难度较大,这里方式 1 较容易编程。 在计算最高速率时,由于单方程,双未知数,又不知道波特率为多少,所以要综合各方面的条件,估 算出 A 和 B 的分频常数,分别为-13 和-14 时,速率不但相同,且为最大值。如下给出 A 机的程序: 代码 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. #include void main( void ) { TMOD = (TMOD & 0x0F) | 0x20; TH1 = -13; //注意用倍频方式 PCON |= 0x80; //SMOD = 1 TR1 = 1; SCON = 0x52; //REN = 1 ES = 1; EA = 1; while( 1 ); 12. } 13. void RS232_intr( void ) interrupt 4 14. { 15. 16. 17. 18. 19. 20. unsigned char rDat; if( RI == 1 ){ RI=0; rDat=SBUF; } if( TI==1 ) { static unsigned char tDat=‘a’; SBUF = tDat; //注意 RI 和 TI 任一位变为 1 都中断 21. 22. 23. 24. } } TI = 0; If( ++Dat > ‘z’) Dat=‘a’; 四、 多机通位 在方式 2 和方式 3,SM2 只对接收有影 响,当 SM2=1 时,只接收第 9 位等于 1 的帧(伪地址帧), 而 SM2=0 时,第 9 位不影响接收。λ 多机通信中,地址的确认与本机程序有关,所以可以实现点对点、点对组、以及通播方式的通信。λ 如果收发共用一总线,任何时刻只有一个发送源能占用总线发送数据,否则发生冲突。由此可构造无 竞争的令牌网;或者多主竞争总线网。λ 1

110,580

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧