我正在使用运行Windows IoT的Raspberry Pi 3。我连接了一个DS18B20传感器,我可以通过UWP应用程序与它进行通信。
我现在想把这个应用程序变成BackgroundTask应用程序。 我正在使用此代码用于OneWire coms
class WireSearchResult
{
public byte[] id = new byte[8];
public int lastForkPoint = 0;
}
public class OneWire
{
private SerialDevice serialPort = null;
DataWriter dataWriteObject = null;
DataReader dataReaderObject = null;
public async Task<string> GetFirstSerialPort()
{
try
{
string aqs = SerialDevice.GetDeviceSelector("UART0");
var dis = await DeviceInformation.FindAllAsync(aqs);
if (dis.Count > 0)
{
var deviceInfo = dis.First();
return deviceInfo.Id;
}
}
catch (Exception ex)
{
Debug.WriteLine("Unable to get serial device: " + ex.Message);
}
return null;
}
public void shutdown()
{
if (serialPort != null)
{
serialPort.Dispose();
serialPort = null;
}
}
async Task<bool> onewireReset(string deviceId)
{
try
{
if (serialPort != null)
serialPort.Dispose();
serialPort = await SerialDevice.FromIdAsync(deviceId);
// Configure serial settings
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 9600;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
dataWriteObject = new DataWriter(serialPort.OutputStream);
dataWriteObject.WriteByte(0xF0);
await dataWriteObject.StoreAsync();
dataReaderObject = new DataReader(serialPort.InputStream);
await dataReaderObject.LoadAsync(1);
byte resp = dataReaderObject.ReadByte();
if (resp == 0xFF)
{
System.Diagnostics.Debug.WriteLine("Nothing connected to UART");
return false;
}
else if (resp == 0xF0)
{
System.Diagnostics.Debug.WriteLine("No 1-wire devices are present");
return false;
}
else
{
//System.Diagnostics.Debug.WriteLine("Response: " + resp);
serialPort.Dispose();
serialPort = await SerialDevice.FromIdAsync(deviceId);
// Configure serial settings
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 115200;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
dataWriteObject = new DataWriter(serialPort.OutputStream);
dataReaderObject = new DataReader(serialPort.InputStream);
return true;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
return false;
}
}
public async Task onewireWriteByte(byte b)
{
for (byte i = 0; i < 8; i++, b = (byte)(b >> 1))
{
// Run through the bits in the byte, extracting the
// LSB (bit 0) and sending it to the bus
await onewireBit((byte)(b & 0x01));
}
}
async Task<byte> onewireBit(byte b)
{
var bit = b > 0 ? 0xFF : 0x00;
dataWriteObject.WriteByte((byte)bit);
await dataWriteObject.StoreAsync();
await dataReaderObject.LoadAsync(1);
var data = dataReaderObject.ReadByte();
return (byte)(data & 0xFF);
}
async Task<byte> onewireReadByte()
{
byte b = 0;
for (byte i = 0; i < 8; i++)
{
// Build up byte bit by bit, LSB first
b = (byte)((b >> 1) + 0x80 * await onewireBit(1));
}
// System.Diagnostics.Debug.WriteLine("onewireReadByte result: " + b);
return b;
}
public async Task<double> getTemperature(string deviceId)
{
double tempCelsius = -200;
if (await onewireReset(deviceId))
{
await onewireWriteByte(0xCC); //1-Wire SKIP ROM command (ignore device id)
await onewireWriteByte(0x44); //DS18B20 convert T command
// (initiate single temperature conversion)
// thermal data is stored in 2-byte temperature
// register in scratchpad memory
// Wait for at least 750ms for data to be collated
await Task.Delay(750);
// Get the data
await onewireReset(deviceId);
await onewireWriteByte(0xCC); //1-Wire Skip ROM command (ignore device id)
await onewireWriteByte(0xBE); //DS18B20 read scratchpad command
// DS18B20 will transmit 9 bytes to master (us)
// starting with the LSB
byte tempLSB = await onewireReadByte(); //read lsb
byte tempMSB = await onewireReadByte(); //read msb
// Reset bus to stop sensor sending unwanted data
await onewireReset(deviceId);
// Log the Celsius temperature
tempCelsius = ((tempMSB * 256) + tempLSB) / 16.0;
var temp2 = ((tempMSB << 8) + tempLSB) * 0.0625; //just another way of calculating it
System.Diagnostics.Debug.WriteLine("Temperature: " + tempCelsius + " degrees C " + temp2);
}
return tempCelsius;
}
}
最后是StartupTask
public sealed class StartupTask : IBackgroundTask
{
private BackgroundTaskDeferral deferral;
private OneWire onewire;
private string deviceId = string.Empty;
private bool inprog = false;
private Timer timer;
public void Run(IBackgroundTaskInstance taskInstance)
{
deferral = taskInstance.GetDeferral();
onewire = new OneWire();
deviceId = await onewire.GetFirstSerialPort();
if(deviceId != null)
await onewire.getTemperature(deviceId));
BackgroundTaskDeferral.Complete();
}
}
我遇到的问题是,当我运行此代码时,它会挂在处理SerialDevice
类中OneWire
的其中一行。
我在一些地方读过它与BackgroundTask相关并使用Async / Await
答案 0 :(得分:0)
此问题与BackgroundTask无关。因为您的代码在非BackgroundTask(app)中产生相同的问题。
其原因看起来像SerialPort is somewhat prone to deadlock。
我发现有太多的onewireReset
方法调用关闭并重新打开SerialPort。我不知道为什么要这样做但这导致了问题。
所以有一个解决方法:重写相关的部分逻辑并确保在程序开始时打开SerialPort并在你不再需要它时将其处理掉。
答案 1 :(得分:0)
我在后台任务中使用相同的onewire代码与DS18B20传感器通信,并且遇到与您完全相同的行为。
我发现如果我在调用串口配置方法之前放置100毫秒的延迟它会起作用
await Task.Delay(100)
我尝试了不到100毫秒,但它只是一直挂着。
此stackoverflow问题第一个答案解释了.Net Framework中Why Thread.Sleep() before SerialPort.Open and Close?
中串行端口的问题答案 2 :(得分:0)
我昨天遇到了完全相同的问题(程序在 onewireReset(...)方法中处理SerialDevice对象时突然挂起)我设法解决了它。
解决方案原则: 不要不断处理/重新获取串口。相反,根据需要获取端口一次并动态重新配置(=更改波特率)。这样就可以完全避免挂起 SerialDevice.Dispose()调用。
注意:为了能够更改波特率,您必须首先从端口分离 DataReader 和 DataWriter 对象流,或者你会得到一个例外。更改后,重新附加新的 DataReader 和 DataWriter 对象(记得妥善处理旧对象)。
修改后的OneWire类:
public class OneWire
{
private SerialDevice serialPort = null;
DataWriter dataWriteObject = null;
DataReader dataReaderObject = null;
public void shutdown()
{
if (serialPort != null)
{
serialPort.Dispose();
serialPort = null;
}
}
private async Task ReconfigurePort(uint baudRate, string deviceId)
{
if (serialPort == null)
{
serialPort = await SerialDevice.FromIdAsync(deviceId);
serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = baudRate;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
serialPort.Handshake = SerialHandshake.None;
dataWriteObject = new DataWriter(serialPort.OutputStream);
}
else
{
dataWriteObject.DetachStream();
dataWriteObject.DetachBuffer();
dataWriteObject.Dispose();
dataReaderObject.DetachStream();
dataReaderObject.Dispose();
serialPort.BaudRate = baudRate;
dataWriteObject = new DataWriter(serialPort.OutputStream);
}
}
async Task<bool> onewireReset(string deviceId)
{
try
{
await ReconfigurePort(9600, deviceId);
dataWriteObject.WriteByte(0xF0);
await dataWriteObject.StoreAsync();
dataReaderObject = new DataReader(serialPort.InputStream);
await dataReaderObject.LoadAsync(1);
byte resp = dataReaderObject.ReadByte();
if (resp == 0xFF)
{
//System.Diagnostics.Debug.WriteLine("Nothing connected to UART");
return false;
}
else if (resp == 0xF0)
{
//System.Diagnostics.Debug.WriteLine("No 1-wire devices are present");
return false;
}
else
{
//System.Diagnostics.Debug.WriteLine("Response: " + resp);
await ReconfigurePort(115200, deviceId);
dataReaderObject = new DataReader(serialPort.InputStream);
return true;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception: " + ex.Message);
return false;
}
}
public async Task onewireWriteByte(byte b)
{
for (byte i = 0; i < 8; i++, b = (byte)(b >> 1))
{
// Run through the bits in the byte, extracting the
// LSB (bit 0) and sending it to the bus
await onewireBit((byte)(b & 0x01));
}
}
async Task<byte> onewireBit(byte b)
{
var bit = b > 0 ? 0xFF : 0x00;
dataWriteObject.WriteByte((byte)bit);
await dataWriteObject.StoreAsync();
await dataReaderObject.LoadAsync(1);
var data = dataReaderObject.ReadByte();
return (byte)(data & 0xFF);
}
async Task<byte> onewireReadByte()
{
byte b = 0;
for (byte i = 0; i < 8; i++)
{
// Build up byte bit by bit, LSB first
b = (byte)((b >> 1) + 0x80 * await onewireBit(1));
}
//System.Diagnostics.Debug.WriteLine("onewireReadByte result: " + b);
return b;
}
public async Task<double> getTemperature(string deviceId)
{
double tempCelsius = -200;
if (await onewireReset(deviceId))
{
await onewireWriteByte(0xCC); //1-Wire SKIP ROM command (ignore device id)
await onewireWriteByte(0x44); //DS18B20 convert T command
// (initiate single temperature conversion)
// thermal data is stored in 2-byte temperature
// register in scratchpad memory
// Wait for at least 750ms for data to be collated
//await Task.Delay(250);
// Get the data
await onewireReset(deviceId);
await onewireWriteByte(0xCC); //1-Wire Skip ROM command (ignore device id)
await onewireWriteByte(0xBE); //DS18B20 read scratchpad command
// DS18B20 will transmit 9 bytes to master (us)
// starting with the LSB
byte tempLSB = await onewireReadByte(); //read lsb
byte tempMSB = await onewireReadByte(); //read msb
// Reset bus to stop sensor sending unwanted data
await onewireReset(deviceId);
// Log the Celsius temperature
tempCelsius = ((tempMSB * 256) + tempLSB) / 16.0;
var temp2 = ((tempMSB << 8) + tempLSB) * 0.0625; //just another way of calculating it
//System.Diagnostics.Debug.WriteLine("Temperature: " + tempCelsius + " degrees C " + temp2);
}
return tempCelsius;
}
}