编程技巧:Java串口通信简介

编程技巧:Java串口通信简介,第1张

嵌入式系统或传感器网络的很多应用和测试都需要通过PC机与嵌入式设备或传感器节点进行通信 其中 最常用的接口就是RS 串口和并口(鉴于USB接口的复杂性以及不需要很大的数据传输量 USB接口用在这里还是显得过于奢侈 况且目前除了SUN有一个支持USB的包之外 我还没有看到其他直接支持USB的Java类库) SUN的CommAPI分别提供了对常用的RS 串行端口和IEEE 并行端口通讯的支持 RS C(又称EIA RS C 以下简称RS )是在 年由美国电子工业协会(EIA)联合贝尔系统 调制解调器厂家及计算机终端生产厂家共同制定的用于串行通讯的标准 RS 是一个全双工的通讯协议 它可以同时进行数据接收和发送的工作

常见的Java串口包

目前 常见的Java串口包有SUN在 年发布的串口通信API m jar(Windows下) m jar(Linux/Solaris);IBM的串口通信API以及一个开源的实现 鉴于在Windows下SUN的API比较常用以及IBM的实现和SUN的在API层面都是一样的 那个开源的实现又不像两家大厂的产品那样让人放心 这里就只介绍SUN的串口通信API在Windows平台下的使用

串口包的安装(Windows下)

到SUN的网站下载javam win zip 包含的东西如下所示

按照其使用说明(l)的说法 要想使用串口包进行串口通信 除了设置好环境变量之外 还要将win dll复制到 \bin目录下;将m jar复制到 \lib;把m properties也同样拷贝到 \lib目录下 然而在真正运行使用串口包的时候 仅作这些是不够的 因为通常当运行 java MyApp 的时候 是由JRE下的虚拟机启动MyApp的 而我们只复制上述文件到JDK相应目录下 所以应用程序将会提示找不到串口 解决这个问题的方法很简单 我们只须将上面提到的文件放到JRE相应的目录下就可以了

值得注意的是 在网络应用程序中使用串口API的时候 还会遇到其他更复杂问题 有兴趣的话 你可以查看CSDN社区中 关于网页上Applet用javam 读取客户端串口的问题 的帖子

串口API概览

m CommPort

这是用于描述一个被底层系统支持的端口的抽象类 它包含一些高层的IO控制方法 这些方法对于所有不同的通讯端口来说是通用的 SerialPort 和ParallelPort都是它的子类 前者用于控制串行端口而后者用于控这并口 二者对于各自底层的物理端口都有不同的控制方法 这里我们只关心SerialPort

m CommPortIdentifier

这个类主要用于对串口进行管理和设置 是对串口进行访问控制的核心类 主要包括以下方法

l 确定是否有可用的通信端口

l 为IO *** 作打开通信端口

l 决定端口的所有权

l 处理端口所有权的争用

l 管理端口所有权变化引发的事件(Event)

m SerialPort

这个类用于描述一个RS 串行通信端口的底层接口 它定义了串口通信所需的最小功能集 通过它 用户可以直接对串口进行读 写及设置工作

串口API实例

大段的文字怎么也不如一个小例子来的清晰 下面我们就一起看一下串口包自带的例子 SerialDemo中的一小段代码来加深对串口API核心类的使用方法的认识

列举出本机所有可用串口

     void listPortChoices() { CommPortIdentifier portId; Enumeration en = CommPortIdentifier getPortIdentifiers(); // iterate through the ports while (en hasMoreElements()) { portId = (CommPortIdentifier) en nextElement(); if (portId getPortType() == CommPortIdentifier PORT_SERIAL) { System out println(portId getName()); } } portChoice select(parameters getPortName()); }

以上代码可以列举出当前系统所有可用的串口名称 我的机器上输出的结果是 和

串口参数的配置

串口一般有如下参数可以在该串口打开以前配置进行配置

包括波特率 输入/输出流控制 数据位数 停止位和齐偶校验

SerialPort sPort; try { sPort setSerialPortParams(BaudRate Databits Stopbits Parity); //设置输入/输出控制流 sPort setFlowControlMode(FlowControlIn | FlowControlOut); } catch (UnsupportedCommOperationException e) {}

串口的读写

对串口读写之前需要先打开一个串口

     CommPortIdentifier portId = CommPortIdentifier getPortIdentifier(PortName); try { SerialPort sPort = (SerialPort) portId open( 串口所有者名称  超时等待时间); } catch (PortInUseException e) {//如果端口被占用就抛出这个异常 throw new SerialConnectionException(e getMessage()); } //用于对串口写数据 OutputStream os = new BufferedOutputStream(sPort getOutputStream()); os write(int data); //用于从串口读数据 InputStream is = new BufferedInputStream(sPort getInputStream()); int receivedData = is read();

读出来的是int型 你可以把它转换成需要的其他类型

这里要注意的是 由于Java语言没有无符号类型 即所有的类型都是带符号的 在由byte到int的时候应该尤其注意 因为如果byte的最高位是 则转成int类型时将用 来占位 这样 原本是 的byte类型的数变成int型就成了 这是很严重的问题 应该注意避免

串口通信的通用模式及其问题

终于唠叨完我最讨厌的基础知识了 下面开始我们本次的重点 串口应用的研究 由于向串口写数据很简单 所以这里我们只关注于从串口读数据的情况 通常 串口通信应用程序有两种模式 一种是实现SerialPortEventListener接口 监听各种串口事件并作相应处理;另一种就是建立一个独立的接收线程专门负责数据的接收 由于这两种方法在某些情况下存在很严重的问题(至于什么问题这里先卖个关子J) 所以我的实现是采用第三种方法来解决这个问题

事件监听模型

现在我们来看看事件监听模型是如何运作的

l 首先需要在你的端口控制类(例如SManager)加上 implements SerialPortEventListener

l 在初始化时加入如下代码

     try { SerialPort sPort addEventListener(SManager); } catch (TooManyListenersException e) { sPort close(); throw new SerialConnectionException( too many listeners added ); } sPort notifyOnDataAvailable(true);

l 覆写public void serialEvent(SerialPortEvent e)方法 在其中对如下事件进行判断

BI 通讯中断

CD 载波检测

CTS 清除发送

DATA_AVAILABLE 有数据到达

DSR 数据设备准备好

FE 帧错误

OE 溢位错误

OUTPUT_BUFFER_EMPTY 输出缓冲区已清空

PE 奇偶校验错

RI振铃指示

一般最常用的就是DATA_AVAILABLE 串口有数据到达事件 也就是说当串口有数据到达时 你可以在serialEvent中接收并处理所收到的数据 然而在我的实践中 遇到了一个十分严重的问题

首先描述一下我的实验 我的应用程序需要接收传感器节点从串口发回的查询数据 并将结果以图标的形式显示出来 串口设定的波特率是 川口每隔 毫秒返回一组数据(大约是 字节左右) 周期(即持续时间)为 秒 实测的时候在一个周期内应该返回 多个字节 而用事件监听模型我最多只能收到不到 字节 不知道这些字节都跑哪里去了 也不清楚到底丢失的是那部分数据 值得注意的是 这是我将serialEvent()中所有处理代码都注掉 只剩下打印代码所得的结果 数据丢失的如此严重是我所不能忍受的 于是我决定采用其他方法

串口读数据的线程模型

这个模型顾名思义 就是将接收数据的 *** 作写成一个线程的形式:

      public void startReadingDataThread() { Thread readDataProcess = new Thread(new Runnable() { public void run() { while (newData !=  ) { try { newData = is read(); System out println(newData); //其他的处理过程 ……… } catch (IOException ex) { System err println(ex); return; } } readDataProcess start(); }

在我的应用程序中 我将收到的数据打包放到一个缓存中 然后启动另一个线程从缓存中获取并处理数据 两个线程以生产者—消费者模式协同工作 数据的流向如下图所示

这样 我就圆满解决了丢数据问题 然而 没高兴多久我就又发现了一个同样严重的问题 虽然这回不再丢数据了 可是原本一个周期( 秒)之后 传感器节电已经停止传送数据了 但我的串口线程依然在努力的执行读串口 *** 作 在控制台也可以看见收到的数据仍在不断的打印 原来 由于传感器节点发送的数据过快 而我的接收线程处理不过来 所以InputStream就先把已到达却还没处理的字节缓存起来 于是就导致了明明传感器节点已经不再发数据了 而控制台却还能看见数据不断打印这一奇怪的现象 唯一值得庆幸的是最后收到数据确实是 左右字节 没出现丢失现象 然而当处理完最后一个数据的时候已经快 分半钟了 这个时间远远大于节点运行周期 这一延迟对于一个实时的显示系统来说简直是灾难!

后来我想 是不是由于两个线程之间的同步和通信导致了数据接收缓慢呢于是我在接收线程的代码中去掉了所有处理代码 仅保留打印收到数据的语句 结果依然如故 看来并不是线程间的通信阻碍了数据的接收速度 而是用线程模型导致了对于发送端数据发送速率过快的情况下的数据接收延迟 这里申明一点 就是对于数据发送速率不是如此快的情况下前面者两种模型应该还是好用的 只是特殊情况还是应该特殊处理

第三种方法

痛苦了许久(Boss天天催我L)之后 偶然的机会 我听说TinyOS中(又是开源的)有一部分是和我的应用程序类似的串口通信部分 于是我下载了它的 x版的Java代码部分 参考了它的处理方法 解决问题的方法说穿了其实很简单 就是从根源入手 根源不就是接收线程导致的吗 那好 我就干脆取消接收线程和作为中介的共享缓存 而直接在处理线程中调用串口读数据的方法来解决问题(什么 为什么不把处理线程也一并取消 都取消应用程序界面不就锁死了吗所以必须保留)于是程序变成了这样

public byte[] getPack(){ while (true) { // PacketLength为数据包长度 byte[] msgPack = new byte[PacketLength]; for(int i =  ; i < PacketLength; i++){ if( (newData = is read()) !=  ){ msgPack[i] = (byte) newData; System out println(msgPack[i]); } } return msgPack; } }

在处理线程中调用这个方法返回所需要的数据序列并处理之 这样不但没有丢失数据的现象行出现 也没有数据接收延迟了 这里唯一需要注意的就是当串口停止发送数据或没有数据的时候is read()一直都返回 如果一旦在开始接收数据的时候发现 就不要理它 继续接收 直到收到真正的数据为止

结束语

lishixinzhi/Article/program/Java/hx/201311/26605

计算机程序设计是一门计算机基础课。主要学习了以下四部分:

1、计算机程序设计的背景介绍。计算机程序设计这门课,最开始会介绍这门课程的相关背景,了解其发展历史。介绍一些计算机程序设计的思想。毕竟人的思想和计算机还是有所不同的。因此,了解其背景很重要。

2、程序设计的算法。计算机程序设计的算法,算法代表着用系统的方法描述解决问题的策略机制。我们解决问题需要有思路,算法能帮助我们解决问题。

3、编程语言的相关知识。一般计算机程序设计,学习的编程语言是C语言。C语言主要有这些内容:“运算符、优先级与结合性、自增自减的运用、算法的基本控制结构、函数、指针、结构体”。其中,指针是C语言的难点,必须好好学习,才能灵活运用C语言。

4、如何运用编程语言解决问题。编程语言只是工具,我们要学会运用编程语言解决问题。合理掌握编程语言,具体问题具体分析,这样这门课才算是学懂了。所以在学会编程语言之后,会学一些方法,来根据所学编程语言解决问题。

微信小程序,简称小程序,英文名Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用"触手可及"的梦想,用户扫一扫或搜一下即可打开应用。下面简单介绍一下开发入门

一、注册小程序账号

1、进入微信公众平台 2、点击立即注册

3、选择小程序 4、填写信息注册即可 5、绑定开发者 6进入“设置-开发设置”,获取AppID信息。 二、下载微信web开发者工具 1点击小程序后的查看详情 2、选择开发者工具 3、下载对应系统版本的应用程序 4、安装开发工具 三、编写小程序实例 1、打开工具点击小程序项目 2、填写相应信息,点击确定 3、实例目录结构 4、appjs是小程序的脚本代码(必须),可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量,调用框架提供的丰富的 API。 5、appjson是对整个小程序的全局配置(必须),用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多tab等。接受一个数组,每一项都是字符串,来指定小程序由哪些页面组成。微信小程序中的每一个页面的路径+页面名都需要写在appjson的pages中,且pages中的第一个页面是小程序的首页。 6、appwxss是整个小程序的公共样式表(非必须)。 7、indexjs 是页面的脚本文件(必须),在这个文件中我们可以监听并处理页面的生命周期函数、获取小程序实例,声明并处理数据,响应页面交互事件等。 8、indexwxml是页面结构文件(必须)。 9、indexwxss是页面样式表文件(非必须),当有页面样式表时,页面的样式表中的样式规则会层叠覆盖appwxss中的样式规则。如果不指定页面的样式表,也可以在页面的结构文件中直接使用appwxss中指定的样式规则。 10、在编辑配置好后点击真机调试 11、手机微信扫描二维码 12、自动d出调试窗口,通过真机调试能够更好的测试小程序

参考程序,可以调节时间,设置闹钟,音乐闹铃

#include<reg52h>

#include<INTRINSH>

//

#define uchar unsigned char

#define uint unsigned int

#define TIME (0X10000-50000)

#define FLAG 0XEF //闹钟标志

//

//引脚连接图

sbit CLK=P1^2;

sbit RST=P1^4;

sbit DAT=P1^3;

sbit RS=P1^5;

sbit RW=P1^6;

sbit E=P1^7;

sbit P32=P3^2;

sbit KEY1 = P2^7;

sbit KEY2 = P2^6;

sbit KEY3 = P2^5;

sbit KEY4 = P2^4;

sbit ACC_7=ACC^7;

//

//全局变量及常量定义

uchar i=20,j;

uchar DataBuf[16] = {};//日期

uchar TimeBuf[16] = {};//时间

uchar alarm[2],time[3];

uchar code Day[]={31,28,31,30,31,30,31,31,30,31,30,31};//12个月的最大日期(非闰年)

//闰年月星期表

const unsigned char WeekTab[] = {

(3 << 5) + 31,///1月

(6 << 5) + 29,///2月

(0 << 5) + 31,///3月

(3 << 5) + 30,///4月

(5 << 5) + 31,//5月

(1 << 5) + 30,//6月

(3 << 5) + 31,//7月

(6 << 5) + 31,//8月

(1 << 5) + 30,//9月

(4 << 5) + 31,//10月

(0 << 5) + 30,//11月

(2 << 5) + 31 //12月

};

//音律表

uint code table1[]={64260,64400,64524,64580,64684,64777,

64820,64898,64968,65030,65058,65110,65157,65178,65217};

//发声部分的延时时间

uchar code table2[]={0x82,1,0x81,0xf4,0xd4,0xb4,0xa4,

0x94,0xe2,1,0xe1,0xd4,0xb4,0xc4,0xb4,4,0};

//闹钟中用的全局变量

uchar th1,tl1;

//

//延时1ms函数

delay1ms(uchar time)

{

uchar i,j;

for(i=0;i<time;i++)

{

for(j=0;j<250;j++);

}

}

//

//LCD控制函数

Enable()

{

RS=0;

RW=0;

E=0;

delay1ms(3);

E=1;

}

//

//LCD1602写入字符函数

LCD1602_WriteSChr(uchar i)

{

P0=i;

RS=1;

RW=0;

E=0;

delay1ms(2);

E=1;

}

//

//LCD1602写入字符串函数

//入口函数

//uchar data address : 写入数据首地址

//ucharm:写入字节数

LCD1602_WriteStr(uchar address,uchar m)

{

uchar i,j;

for(i=0;i<m;i++,address++)

{

j=address;

LCD1602_WriteSChr(j);

}

}

//

//LCD显示

void LCDShow(void)

{

P0=0XC; //显示器开、光标关

Enable();

//P0=0x80; //写入显示起始地址

//Enable();

//LCD1602_WriteStr(DataBuf,16); //写入日期显示缓存

P0=0xc1; //写入显示起始地址

Enable();

LCD1602_WriteStr(TimeBuf,16); //写入时间显示缓存

}

//

//DS1302写入子程序

void DS1302_Write(uchar temp)

{

uchar i;

CLK=0; //将DS1320时钟脉冲拉低

_nop_();//延时一指令周期

RST=1; //RST置高电平

_nop_();//延时一指令周期

for(i=0;i<8;i++) //循环8次

{

DAT=temp&0x01; //向DS1302写入一字节数据

_nop_(); //延时一指令周期

CLK=1; //拉高时钟脉冲

temp>>=1; //右移一位

CLK=0; //拉低时钟脉冲

}

}

//

//DS1302读取子程序

uchar DS1302_Read()

{

uchar i,j=0;

for(i=0;i<8;i++)//循环8次

{

j>>=1; //右移一位

_nop_(); //延时一指令周期

CLK=0; //拉低时钟脉冲

_nop_(); //延时一指令周期

if(DAT) //判断接收该位数据是否为1

j|=0x80;//该位置1

_nop_(); //延时一指令周期

CLK=1; //拉高时钟脉冲

}

return(j); //返回数值

}

//

//部分显示数据初始化

TimeStart()

{

TimeBuf[0]=TimeBuf[8]=TimeBuf[9]=TimeBuf[10]=0x20; //不显示字符

TimeBuf[2]=TimeBuf[5]=':'; //时间分隔显示

DS1302_Write(0xc1);

alarm[0]=DS1302_Read();

RST=0;

DS1302_Write(0xc3);

alarm[1]=DS1302_Read();

RST=0;

DS1302_Write(0xc5);

DataBuf[0]=DS1302_Read();

RST=0;

}

//

//读取时间

ReadTime()

{

uchar i,m,n;

for(m=0,i=0,n=0x85;i<7;i+=3,n-=2,m++) //连续读取时,分,秒

{

DS1302_Write(n); //写入读取寄存器指令

time[m]=DS1302_Read(); //读取数据

RST=0; //将RST电平拉低,停止传输

TimeBuf[i]=time[m]/16+0x30; //将两位数据的十位转为字符格式

TimeBuf[i+1]=time[m]%16+0x30;//将两位数据的个位转为字符格式

}

}

//

//功能选择超时定时器

time0() interrupt 1 using 1

{

i--;

if(i==0)

{

if(j!=0)

j--;

i=20;

}

TH0=TIME/256,TL0=TIME%256;

}

//

//产生闹铃音调

intime1() interrupt 3

{

TH1=th1,TL1=tl1;

P32=!P32;

}

//

//闹钟显示

void AlarmShow(void)

{

uchar i,j,a,b,n;

ET1=1;

for(j=0;j<6;j++)

{

i=0;

while(1)

{

a=table2[i];

if(a==0)

break;

b=a&0xf;

a>>=4;

if(a==0)

{

TR1=0;

goto D1;

}

a=((--a)<<1)/2;

TH1=th1=table1[a]/256,TL1=tl1=table1[a]%256;

TR1=1;

D1: do

{

b--;

for(n=0;n<3;n++)

{

ReadTime();

LCDShow();

P2=0xff;

if(KEY4 == 1)

{

delay1ms(100);

if(KEY4 == 1)

{

TR1=0;

ET1=0;

P32 = 1;

return;

}

}

}

}while(b!=0);

i++;

}

TR1=0;

}

ET1=0;

}

//

//设置日期、时间

void SetTime(void)

{

uchar i=0xc2,year,month,day,n;

TimeBuf[6]=TimeBuf[7]=0x30;

DataBuf[14]=DataBuf[15]=0x20;

LCDShow();

while(1)

{

P0=0xe; //显示器开、光标开

Enable();

P0=i; //定光标

Enable();

P2=0xff;

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1)||(KEY4 == 1))

{

delay1ms(100); //延时01s去抖动

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1)||(KEY4 == 1))

{

j=7;

if(KEY1 == 1)

{

i+=3; //更改设置项目

if(i==0x8e)

i=0xc2;

else if(i>0xc5)

i=0xc2;

}

else if(KEY2 == 1)

{

year=(DataBuf[4]&0xf)10+(DataBuf[5]&0xf); //将字符格式的年份转换为数值格式

month=(DataBuf[7]&0xf)10+(DataBuf[8]&0xf); //将字符格式的月份转换为数值格式

day=(DataBuf[10]&0xf)10+(DataBuf[11]&0xf); //将字符格式的日数转换为数值格式

if(i==0x85) //设置年份

{

year++;

if(year>99)

year=0;

if((year%4)!=0)

if(month==2&&day==29)

day=28;

}

else if(i==0x88) //设置月份

{

month++;

if(month>12)

month=1;

if(day>Day[month-1])

{

day=Day[month-1];

if(month==2&&(year%4)==0) //计算是否闰年

day=29;

}

}

else if(i==0x8b) //设置日期

{

day++;

if(day>Day[month-1])

{

if(month==2&&(year%4)==0) //计算是否闰年

{

if(day>29)

day=1;

}

if(month!=2)

day=1;

}

}

else if(i==0xc2) //设置小时

{

n=(TimeBuf[0]&0xf)10+(TimeBuf[1]&0xf);

n++;

if(n>23)

n=0;

TimeBuf[0]=n/10+0x30;

TimeBuf[1]=n%10+0x30;

}

else //设置分钟

{

n=(TimeBuf[3]&0xf)10+(TimeBuf[4]&0xf);

n++;

if(n>59)

n=0;

TimeBuf[3]=n/10+0x30;

TimeBuf[4]=n%10+0x30;

}

DataBuf[4]=year/10+0x30; //将数值格式的日期转换为字符形式

DataBuf[5]=year%10+0x30;

DataBuf[7]=month/10+0x30;

DataBuf[8]=month%10+0x30;

DataBuf[10]=day/10+0x30;

DataBuf[11]=day%10+0x30;

LCDShow();

}

else if(KEY3 == 1) //按保存退出键后,向DS1302写入设置后的日期时间

{

DS1302_Write(0x8c);

DS1302_Write((DataBuf[4]&0xf)16+(DataBuf[5]&0xf));

RST=0;

DS1302_Write(0x8a);

DS1302_Write(SetWeek());

RST=0;

for(i=7,n=0x88;i<11;i+=3,n-=2)

{

DS1302_Write(n);

DS1302_Write((DataBuf[i]&0xf)16+(DataBuf[i+1]&0xf));

RST=0;

}

for(i=0;i<7;i+=3,n-=2)

{

DS1302_Write(n);

DS1302_Write((TimeBuf[i]&0xf)16+(TimeBuf[i+1]&0xf));

RST=0;

}

TR0=0;

return;

}

else

{

TR0=0;

return;

}

}

}

if(j==0)

{

TR0=0;

return;

}

}

}

//

//设置闹钟

void SetAlarm(void)

{

uchar i,n;

for(i=1;i<16;i++)

{

DataBuf[i]=0x20;

}

TimeBuf[0]=alarm[0]/16+0x30;

TimeBuf[1]=(alarm[0]&0xf)+0x30;

TimeBuf[3]=alarm[1]/16+0x30;

TimeBuf[4]=(alarm[1]&0xf)+0x30;

TimeBuf[6]=TimeBuf[7]=0x30;

LCDShow();

i=0xc2;

while(1)

{

P0=0xe; //显示器开、光标开

Enable();

P0=i; //定光标

Enable();

P2=0xff;

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1)||(KEY4 == 1))

{

delay1ms(100); //延时01s去抖动

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1)||(KEY4 == 1))

{

j=7;

if(KEY1 == 1)

{

i+=3;

if(i>0xc5)

i=0xc2;

}

else if(KEY2 == 1)

{

if(i==0xc2)

{

n=(TimeBuf[0]&0xf)10+(TimeBuf[1]&0xf);

n++;

if(n>23)

n=0;

TimeBuf[0]=n/10+0x30;

TimeBuf[1]=n%10+0x30;

}

else

{

n=(TimeBuf[3]&0xf)10+(TimeBuf[4]&0xf);

n++;

if(n>59)

n=0;

TimeBuf[3]=n/10+0x30;

TimeBuf[4]=n%10+0x30;

}

LCDShow();

}

else if(KEY3 == 1)

{

DS1302_Write(0xc0);

DS1302_Write((TimeBuf[0]&0xf)16+(TimeBuf[1]&0xf));

RST=0;

DS1302_Write(0xc2);

DS1302_Write((TimeBuf[3]&0xf)16+(TimeBuf[4]&0xf));

RST=0;

DataBuf[0]=FLAG;

DS1302_Write(0xc4);

DS1302_Write(DataBuf[0]);

RST=0;

TR0=0;

TimeStart();

return;

}

else

{

TR0=0;

TimeStart();

return;

}

}

}

if(j==0)

{

TR0=0;

TimeStart();

return;

}

}

}

//

//DS1302初始化程序

void DS1302_Init(void)

{

uchar i,n;

DS1302_Write(0x8c);

DS1302_Write((DataBuf[4]&0xf)16+(DataBuf[5]&0xf));

RST=0;

DS1302_Write(0x8a);

DS1302_Write(SetWeek());

RST=0;

for(i=7,n=0x88;i<11;i+=3,n-=2)

{

DS1302_Write(n);

DS1302_Write((DataBuf[i]&0xf)16+(DataBuf[i+1]&0xf));

RST=0;

}

for(i=0;i<7;i+=3,n-=2)

{

DS1302_Write(n);

DS1302_Write((TimeBuf[i]&0xf)16+(TimeBuf[i+1]&0xf));

RST=0;

}

}

//

//主函数

main()

{

IE=0x82;

TMOD=0x11;

DS1302_Write(0x8E); //禁止写保护

DS1302_Write(0);

RST=0;

P0=1; //清屏并光标复位

Enable();

P0=0x38; //设置显示模式:8位2行5x7点阵

Enable();

P0=6; //文字不动,光标自动右移

Enable();

DS1302_Init();

TimeStart();

while(1)

{

ReadTime(); //读取时间

LCDShow(); //显示时间

if(DataBuf[0]!=0x20)

if(time[0]==alarm[0])

if(time[1]==alarm[1])

if(time[2]==0)

AlarmShow();

P2=0xff;

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1))

{

delay1ms(100); //延时01s去抖动

if((KEY1 == 1)||(KEY2 == 1)||(KEY3 == 1))

{

j=7;

TH0=TIME/256,TL0=TIME%256;

TR0=1;

if(KEY1 == 1)

{

SetTime();

}

else if(KEY2 == 1)

{

SetAlarm();

}

else if(KEY3 == 1)

{

TR0=0;

if(DataBuf[0]==FLAG)

DataBuf[0]=0x20;

else

DataBuf[0]=FLAG;

DS1302_Write(0xc4);

DS1302_Write(DataBuf[0]);

RST=0;

}

}

}

delay1ms(100);

}

}

周期20毫秒,占空比5%~10%,所以高电平为1ms~2ms,以1%变化为调节量(200us)计算来设计程序。

#include<reg51h>

#define uchar unsigned char

sbit pwm=P1^0;

uchar u_p=5,num=0;

void t0isr() interrupt 1

{

num++;

if(num<=u_p)pwm=1;

if(num>u_p)pwm=0;

num%=100;

}

void uart() interrupt 4

{

if(RI)

{

RI=0;

u_p=SBUF;

}

}

main()

{

TMOD=0x22;

TH0=56;

TL0=56;

TH1=0xfd;

TL1=0xfd;

TR0=1;

TR1=1;

ET0=1;

ES=1;

EA=1;

pwm=1;

while(1);

}

4串行E2PROM读写程序

24C64为I2C总线的E2PROM。SCL为400kHz时钟线,SDA为双向数据线,A2、A1、A0三位为片选地址,即I2C总线上最多可并联8个串行E2PROM芯片。对E2PROM的 *** 作方式由读写控制命令字决定,如图4所示。其中"1010"为4位读写控制码,R/W为读写控制位:"0"为写 *** 作,"1"为读 *** 作。所以结合图1可知A2H为写控制命令字,A3H为读控制命令字。

对存储器写 *** 作,首先,单片机向24C64发一个START命令,产生开始条件。然后,发写命令控制字(如A2H)。当24C64接到命令后,进入一个写周期,再由单片机发送存储地址,即确定数据写入到存储器的哪个地址,随后,单片机将要存储的数据送入到SDA数据线上。写周期结束时,单片机再发一停止位(STOP)。

对存储器读 *** 作,首先,单片机向24C64发一个START命令,产生开始条件。然后发写命令控制字(如A2H)。当24C64接到命令后,进入一个写周期,再由单片机发送存储地址。存储地址发送成功后,单片机又向24C64发一个START命令,产生开始条件,然后发读命令控制字(A3H)。当24C64接到命令后,进入一个读周期,单片机从SDA数据线上读出指定存储地址中的数据。读周期结束时,单片机再发一停止位(STOP)。(程序略)

值得注意的是,对存储器 *** 作时,每读写一个字节,单片机必须送一个应答位(ACK),释放一下SDA数据线,以便存储器能继续接收数据。

1程序软件免费下载 

9gsb  

软件,拼音为Ruǎnjiàn,国标中对软件的定义为:与计算机系统 *** 作有关的计算机程序、规程、规则,以及可能有的文件、文档及数据。

MOV DPTR SEGT

START:MOV R0,#1

LOOP: MOV R1,#4

LOOP0:INC R0

MOV A,R0

MOVC A, @A+DPTR;查表取字模

MOV SBUF,A     ;输出字模

NOP                  ;延时等待串行发送全部完成

NOP                 ;

NOP                        ;

NOP                        ;

DJNZ R1,LOOP1  ;

D1s  :MOV R5,#8     ;延迟1秒

LOOP1:MOV R6,#250   ;双字节、单周期

LOOP2:MOV R7,#x     ;双字节、单周期

LOOP3:DJNZ R7,LOOP3 ;双字节、双周期

DJNZ R6,LOOP2 ;双字节、双周期

DJNZ R5,LOOP1 ;双字节、双周期

CJNE R0,#9,LOOP

SJMP START

SEGT: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H

END

以上就是关于编程技巧:Java串口通信简介全部的内容,包括:编程技巧:Java串口通信简介、计算机程序设计主要学什么、微信小程序开发入门教程|微信小程序开发主要技术等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10126513.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存