https://www.cnblogs.com/yangfengwu/p/11087613.html
页面修改成这样子
现在看串口发送数据
点击点亮 发送0xaa 0x55 0x01
我电脑上安装了虚拟串口软件,虚拟出来了COM1和COM2,然后COM1发送的数据会发给COM2 COM2发送的数据会发给COM1
大家如果有两个串口模块也可以
https://jingyan.baidu.com/article/e3c78d648965303c4c85f535.html
那个按钮的程序这样写
测试一下
现在看串口接收数据
说一下哈,这个是上位机的串口中断函数,就是只要接收到数据就会进入这个中断
现在咱读出来接收的数据,然后显示在
读取数据给了好几个方法
咱就说1个,哈哈哈,其实自己一选择方法的时候就有中文注释......
大家注没注意
现在调用一个函数读出来,然后显示出来
ReadExisting() 这个方法就会返回缓冲区里面的所有字节,注意返回的是字符串形式的
调用这个方法就是 serialPort1.ReadExisting(); serialPort1就是咱的
因为咱就是要里面的数据所以
string str = serialPort1.ReadExisting();//读出来当前缓存里面的所有数据
Invoke((new Action(() =>
{
这里面放要操作的主线程的控件的方法
})));
其实这个方法主要是方便解决一个问题,稍候再说,咱先测试一下哈
说明可以了,现在呢,咱去掉
大家可以点开那个 如何跨线程调用 Windows 窗体控件
大家可以看这个https://www.cnblogs.com/yangfengwu/p/5761841.html(最好别看,看了就会感觉麻烦)
4.0之后引进了这种方法
对于初学者知道这个就可以了,像C#,C++,JAVA等等这种高级语言哈,因为可以做界面了,,高级语言规定,操作页面不能在子线程中进行
哪些是子线程呢!..像上面那个串口中断函数,还有自己创建的任务Thread,,,等等吧
好现在,咱接收16进制,
接收到
0xaa 0x55 0x01
0xaa 0x55 0x00
好,上菜
//串口接收到数据就会进入privatevoidserialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
intlen = serialPort1.BytesToRead;//获取可以读取的字节数if(len >0)
{
byte[] recvBytes =newbyte[len];//创建接收的数组serialPort1.Read(recvBytes,0, len);//接收数据if(recvBytes[0] ==0xaa&& recvBytes[1] ==0x55)//判断数据 {
if(recvBytes[2] ==0x01)// {
Invoke((newAction(() => {
button3.Text ="熄灭";
label5.Text ="点亮";
})));
}
elseif(recvBytes[2] ==0x00)
{
Invoke((newAction(() => {
button3.Text ="点亮";
label5.Text ="熄灭";
})));
}
}
}
//string str = serialPort1.ReadExisting();//读出来当前缓存里面的所有数据
//Invoke((new Action(() =>
//{
////显示在文本框里面
// textBox1.AppendText(str);
//})));}
测试
虽然可以了,但是这样写不保险...
原因是那个中断是不定长的数据就进去(受到电脑整体运行状态的影响),所以呢咱优化下
//串口接收到数据就会进入privatevoidserialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
intlen = serialPort1.BytesToRead;//获取可以读取的字节数if(len >0)
{
byte[] recvBytes =newbyte[len];//创建接收的数组serialPort1.Read(recvBytes,0, len);//接收数据for(inti =0; i < len; i++)//拷贝数据到UsartReadBuff {
UsartReadBuff[i+ UsartReadCnt] = recvBytes[i];//从上次的地方接着填入数据 }
UsartReadCnt = UsartReadCnt + len;//记录上次的数据个数if(UsartReadCnt >=3)//接收到可以处理的数据个数 {
UsartReadCnt =0;
if(UsartReadBuff[0] ==0xaa&& UsartReadBuff[1] ==0x55)//判断数据 {
if(UsartReadBuff[2] ==0x01)// {
Invoke((newAction(() => {
button3.Text ="熄灭";
label5.Text ="点亮";
})));
}
elseif(UsartReadBuff[2] ==0x00)
{
Invoke((newAction(() => {
button3.Text ="点亮";
label5.Text ="熄灭";
})));
}
}
}
}
//string str = serialPort1.ReadExisting();//读出来当前缓存里面的所有数据
//Invoke((new Action(() =>
//{
////显示在文本框里面
// textBox1.AppendText(str);
//})));}
自己测试哈
现在说一下
如果接收的是字符串,想显示出来
如果发过来了16进制 注意哈,发过来的是16进制 假设 00 就是数字0 因为那个文本框显示的时候是显示的字符串
所以需要转成 "00" 发过来0F 需要显示字符串形式的 "0F"
给大家准备好了
///<字节数组转16进制字符串>///<param name="bytes"></param>///<returns> String 16进制显示形式</returns>publicstaticstringbyteToHexStr(byte[] bytes)
{
stringreturnStr ="";
try {
if(bytes !=null)
{
for(inti =0; i < bytes.Length; i++)
{
returnStr += bytes[i].ToString("X2");
returnStr +="";//两个16进制用空格隔开,方便看数据 }
}
return returnStr;
}
catch (Exception)
{
return returnStr;
}
}
//串口接收到数据就会进入privatevoidserialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
intlen = serialPort1.BytesToRead;//获取可以读取的字节数if(len >0)
{
byte[] recvBytes =newbyte[len];//创建接收的数组serialPort1.Read(recvBytes,0, len);//接收数据 Invoke((newAction(() =>//显示字符串 {
textBox1.AppendText("字符串:"+Encoding.Default.GetString(recvBytes));//显示在文本框里面 })));
Invoke((newAction(() =>//显示16进制 {
textBox1.AppendText("\r\n16进制:"+ byteToHexStr(recvBytes) +"\r\n");//显示在文本框里面 })));
for(inti =0; i < len; i++)//拷贝数据到UsartReadBuff {
UsartReadBuff[i+ UsartReadCnt] = recvBytes[i];//从上次的地方接着填入数据 }
UsartReadCnt = UsartReadCnt + len;//记录上次的数据个数if(UsartReadCnt >=3)//接收到可以处理的数据个数 {
UsartReadCnt =0;
if(UsartReadBuff[0] ==0xaa&& UsartReadBuff[1] ==0x55)//判断数据 {
if(UsartReadBuff[2] ==0x01)// {
Invoke((newAction(() => {
button3.Text ="熄灭";
label5.Text ="点亮";
})));
}
elseif(UsartReadBuff[2] ==0x00)
{
Invoke((newAction(() => {
button3.Text ="点亮";
label5.Text ="熄灭";
})));
}
}
}
}
}
现在看发送
发送就只做字符串发送哈,,,16进制发送后期补上,,大家先吸收吸收现在的....
执行文件
我把16进制发送用到的函数放在这里,后期再回来加上
///<字符串转16进制格式,不够自动前面补零>//////</summary>///<param name="hexString"></param>///<returns></returns>privatestaticbyte[] strToToHexByte(String hexString)
{
int i;
boolFlag =false;
hexString = hexString.Replace("","");//清除空格if((hexString.Length %2) !=0)
{
Flag =true;
}
if(Flag ==true)
{
byte[] returnBytes =newbyte[(hexString.Length +1) /2];
try {
for(i =0; i < (hexString.Length -1) /2; i++)
{
returnBytes[i] = Convert.ToByte(hexString.Substring(i *2,2),16);
}
returnBytes[returnBytes.Length -1] = Convert.ToByte(hexString.Substring(hexString.Length -1,1).PadLeft(2,'0'),16);
}
catch {
for(i =0; i < returnBytes.Length; i++)
{
returnBytes[i] =0;
}
MessageBox.Show("超过16进制范围A-F,已初始化为0","提示");
}
return returnBytes;
}
else {
byte[] returnBytes =newbyte[(hexString.Length) /2];
try {
for(i =0; i < returnBytes.Length; i++)
{
returnBytes[i] = Convert.ToByte(hexString.Substring(i *2,2),16);
}
}
catch {
for(i =0; i < returnBytes.Length; i++)
{
returnBytes[i] =0;
}
MessageBox.Show("超过16进制范围A-F,已初始化为0","提示");
}
return returnBytes;
}
}
对了,其实上位机串口是有空闲时间中断的(异常捕获),只不过,我还没细研究呢!!!