A digital acoustic sensor is connected to my raspberry.
Everytime it detects sound, it sets the input HIGH.
But it only appears to be active for a couple of milliseconds.
How can i prolong the signal within my program that it stays up for 500ms?
It is a functionality which I know from PLC contollers.
Diagram
Start: sensor input
Q: prolonged signal
,
Here my approach with the answer of Michael:
But still, it doesn't hold for Task.Delay. It goes off directly.
public MainPage()
{
this.InitializeComponent();
GPIOinit();
Serial();
}
private void GPIOinit()
{
const int PIN_AKUSTIK = 19;
GpioController gpio = GpioController.GetDefault(); //GPIO-Controller mit Default belegen
pin_akustik = gpio.OpenPin(PIN_AKUSTIK);
}
public async void Serial()
{
//serial configuration
while (true)
{
//frequency of constant while loop 300ms
Sensor_Akustik();
}
}
public void Sensor_Akustik()
{
pin_akustik.ValueChanged += Pin_ValueChanged;
pin_akustik.SetDriveMode(GpioPinDriveMode.Input);
status_akustik = pin_akustik.Read().ToString();
textblock_DebugAkustik_live.Text = status_akustik;
Messenger.Default.Send<string, Page_Akustik>(status_akustik);
}
private void Pin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
if (args.Edge == GpioPinEdge.RisingEdge)
{
sender.Write(GpioPinValue.High);
Task.Delay(3000).Wait();
}
}
You might refer to following code. You can try to update the latched output value for the pin if the pin is configured as an input.
private void InitGPIO()
{
var gpio = GpioController.GetDefault();
// Show an error if there is no GPIO controller
if (gpio == null)
{
pin = null;
GpioStatus.Text = "There is no GPIO controller on this device.";
return;
}
pin = gpio.OpenPin(LED_PIN);
pin.ValueChanged += Pin_ValueChanged;
pin.SetDriveMode(GpioPinDriveMode.Input);
}
private void Pin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
if(args.Edge == GpioPinEdge.RisingEdge)
{
sender.Write(GpioPinValue.High);
Task.Delay(500).Wait();
}
}
Related
I'm currently working on a project that involve a stepper motor using c# forms and arduino.
I need to know in c# when the motor stops his movement. To do that, I programmed arduino to send a string trough Serial when the movement is finished. Then the string is interpreted by c# so that the app can do other things after that.
I now want to have the same result as the example below, but using async await.
I stored the information that the motor stopped in:
movimentFinished = true;
I solved the problem in a terrible way using: while(movimentFinished = false){await Task.Delay(1)}
The difference between a while loop and an await is going to effect other stuff on my WinApp. The while blocks all the application until movimentFinished == true;
The logic that I want is simple:
MoveMotor();
await "value change"
//do stuff after it finishes
Any help/tip to do that?
Thank you for reading
//this funcion will receive an array from arduino as a reply
private void risposta(object sender, SerialDataReceivedEventArgs e)
{
riceved = port.ReadLine();
rispos = riceved;
this.Invoke(new EventHandler(Reply));
}
//this function will run every time a reply is sent from arduino through serial
private void Reply(object sender, EventArgs e)
{
//string risposValore = rispos.Substring(2, rispos.Length - 2);
char[] pcr = rispos.ToCharArray();
rispos = rispos.Trim();
if (pcr[0] == 'M' && pcr[1] == 'F' && pcr[2] == '1')
{
movementFinished = true;
}
}
//this funcion will send a serial command to arduino to run the motor
public void MoveTheMotor(int position)
{
int command = 1000;
int movement = command + (position)
string com1 = movement.ToString();
port.Write(com1 + "\n");
movementFinished = false;
}
private async void Demo()
{
MoveTheMotor(800);
//this while blocks everything until the value is true
while (movementFinished == false) { await Task.Delay(1); }
//do something after the motor finished
}
Instead of using a boolean, you need a signal. In the blocking world, this would be a ManualResetEventSlim or similar. In the asynchronous world, this would be some form of TaskCompletionSource. As such:
private TaskCompletionSource movementFinished;
private void Reply(object sender, EventArgs e)
{
...
if (pcr[0] == 'M' && pcr[1] == 'F' && pcr[2] == '1')
{
movementFinished.TrySetResult();
}
}
public void MoveTheMotor(int position)
{
...
movementFinished = new TaskCompletionSource();
}
private async void Demo()
{
MoveTheMotor(800);
await movementFinished.Task;
//do something after the motor finished
}
I'm trying to read data from a serial port that I have an Arduino and joystick connected to.
When trying to print out the received data to check if I'm getting it, it continues to print out the same value it was at when it connected.
I am sending data from my serial port in this format: Xaxis:yAxis:switchBool
Heres my C# code in a WPF application
public partial class MainWindow : Window {
public Timer loopTimer;
string comport = "COM7";
SerialPort sp;
public MainWindow() {
InitializeComponent();
SetTimer();
OpenPort();
}
private void SetTimer() {
//Setup the timer
loopTimer = new Timer(500);
// Hook up the Elapsed event for the timer.
loopTimer.Elapsed += TryRead;
loopTimer.AutoReset = true;
loopTimer.Enabled = false;
}
public void OpenPort() {
sp = new SerialPort();
try {
string portName = comport;
sp.PortName = portName;
sp.BaudRate = 9600;
sp.Open();
Debug.WriteLine("Connected");
loopTimer.Enabled = true;
}
catch (Exception) {
MessageBox.Show("Please give a valid port number or check your connection");
loopTimer.Enabled = false;
}
}
public void TryRead(object sender, EventArgs e) {
string s = sp.ReadLine();
Debug.WriteLine(s);
Debug.WriteLine("-");
}
}
Here's my arduino code:
int xPin = A1;
int yPin = A0;
int swPin = A2;
float deadzone = .05;
void setup() {
Serial.begin(9600);
pinMode(swPin, INPUT);
}
void loop() {
float xVal = (((analogRead(xPin) + 1) / 1023.) * 2) -1;
if (xVal < deadzone && xVal > -deadzone ) {
xVal = 0;
}
float yVal = (((analogRead(yPin) + 1) / 1023.) * 2) -1;
if (yVal < deadzone && yVal > -deadzone ) {
yVal = 0;
}
int swVal = analogRead(swPin);
bool switchDown;
if (swVal == 0) {
switchDown = true;
} else {
switchDown = false;
}
Serial.println( String(xVal) + ":" + String(yVal) + ":" + switchDown);
}
Here's an example of what the data should and does look like in the Arduino's serial monitor when moving the thumbstick around:
-1.00:0.70:0
-0.80:0.50:0
-0.70:0.60:0
Running my C# code above and not moving the thumbstick I only get 0.00:0.00:0.00 every time I read, and if I move it before starting I will only receive whatever value that was.
Instead of reading on an interval I would just read whenever new data arrives on the bus. below is an example of how to do that.
SerialPort Port= new SerialPort("Com7");
Port.DataReceived+=OnSerialRecieve;
private void OnSerialRecieve(object sender, SerialDataReceivedEventArgs e)
{
if ((sender as SerialPort).IsOpen)
{
string DataRecieved=(sender as SerialPort).ReadExisting();
}
}
from there you can split it up as you need to. otherwise if you know the exact amount of data your expecting you can sue SerialPort.ReadByte to read exactly the number of bytes you need.
I made a small program that plays back sounds when you press keys.
It uses a global keyboard hook to capture key presses and play back wav files using NAudio.
However playback lags on some computers and plays a few seconds after the key has been pressed. Could this be an HDD/SSD or CPU speed issue or is it a programming issue? What can be done to solve it?
Tried on 4 computers, 2 lagged, 2 did not.
My SSD/i7 - did not lag.
My HDD/Core2Duo - did not lag.
Friend's SSD/i7 - lagged.
Friend's HDD/i7 - lagged.
Program
Info
https://github.com/MattMcManis/Ink
Source
https://github.com/MattMcManis/Ink/tree/master/source/Ink
Download
https://github.com/MattMcManis/Ink/releases
App.xaml.cs
Start the Keyboard Listener.
// Application Startup
//
private void Application_Startup(object sender, StartupEventArgs e)
{
th = new Thread(() => RunKeyListener());
th.IsBackground = true;
th.Start();
th.Join();
}
// Keyboard Listener
//
private void RunKeyListener()
{
KListener.KeyDown += new RawKeyEventHandler(KListener_KeyDown);
}
// Key Down
//
void KListener_KeyDown(object sender, RawKeyEventArgs args)
{
Sound.KeyPressed(args);
}
MainWindow.xaml.cs
KeyboardListener Class is in here.
https://gist.github.com/Ciantic/471698
Sound.cs
private static string wavKeyChar = "Sounds\\character.wav";
private static string wavKeyNum = "Sounds\\number.wav";
public static WaveFileReader wav = null;
public static WaveOutEvent output = null;
// Key Pressed
//
public static void KeyPressed(RawKeyEventArgs args)
{
// Letters
if (args.Key >= Key.A && args.Key <= Key.Z)
{
PlaySound(wavKeyChar);
}
// Numbers
else if (args.Key >= Key.D0 && args.Key <= Key.D9)
{
PlaySound(wavKeyNum);
}
}
// Play Sound
//
public static void PlaySound(string sound)
{
wav = new WaveFileReader(sound);
output = new WaveOutEvent();
output.NumberOfBuffers = 3;
output.DesiredLatency = 500;
output.Init(wav);
output.Play();
}
Try to show a MessageBox or something, to understand if the delayed event is the sound itself or the keypress event.
If the MessageBox shows before the sound is played then it's not a problem of keyboard hook library.
I am very new to the using both I2C and C#/Windows IoT so apologies up front if any of this is a dumb question. I have a Raspberry Pi 3 master and Arduino slave. I am trying to send a value from a slider on my UI form over I2C to the Arduino which I will use to adjust my PWM duty cycle. There a couple of issues I am having and can't work out if its the Pi, Arduino or both.
Here is my Arduino Slave code:
#include <Wire.h>
#define MyAddress 0x03
byte ReceivedData;
int pass;
void setup() {
Wire.begin(MyAddress);
Wire.onReceive(I2CReceived);
Serial.begin(9600);
//Wire.onRequest(I2CRequest);
}
void loop() {
delay(100);
}
void I2CReceived(int NumberOfBytes)
{
/* WinIoT have sent data byte; read it */
byte ReceivedData = Wire.read();
Serial.println(ReceivedData);
if (ReceivedData <= 127){
Serial.println("Equal or under");
return;
}else{
Serial.println("over");
return;
}
}
And my Pi Master:
using System;
using Windows.Devices.Gpio;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;
using Windows.UI.Core;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using System.Diagnostics;
using System.Threading;
namespace I2COutput
{
public sealed partial class MainPage : Page
{
private I2cDevice TransPump;
private Timer periodicTimer;
private const byte pump = 0x03;
double pos;
public MainPage()
{
InitializeComponent();
initcomunica();
}
private async void initcomunica()
{
var pumpset = new I2cConnectionSettings(pump);
pumpset.BusSpeed = I2cBusSpeed.StandardMode;
string aqs = I2cDevice.GetDeviceSelector("I2C1");
var dis = await DeviceInformation.FindAllAsync(aqs);
TransPump = await I2cDevice.FromIdAsync(dis[0].Id, pumpset);
}
private async void SendChange()
{
byte[] sendpos;
try
{
sendpos = BitConverter.GetBytes(pos);
TransPump.Write(sendpos);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
private void tempLbl_SelectionChanged(object sender, RoutedEventArgs e)
{
}
private void slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
pos = slider.Value;
temp2Lbl.Text = pos.ToString();
Convert.ToInt16(pos);
SendChange();
return;
}
}
}
The first issue I am having is that my ReceivedData on the Arduino is always 0 not matter what the value of sendpos is on the Pi (yes, it does change when I move the slider).
The second issue I am having is the first time the slider is moved I get the output on the Arduino serial but then nothing after. If I either reset or reload the Arduino I then get the output of the initial slider change again and nothing after.
Apologies if any of this is too vague or explained poorly, any help or nudge in the right direction would be greatly appreciated.
Thanks in advance.
you have to change the "Wire.onReceive(I2CReceived);" to the loop because when it's in the setup the arduino exute it only one, (sorry for my english)
I wrote an I2C slave for Arduino UNO based on Nick Gammon Web Site.
It worked but I could not get more than 10 K byte /second. You have some missing part in your own code.
Here is stripped down version of the Arduino Code
#include <Wire.h>
#define I2C_400K 1 // http://www.gammon.com.au/forum/?id=10896
bool receiveEventcommandReceived = false;
bool requestEventCommandReceived = false;
int _currentRequestInputParameterLen = 0;
void receiveEvent(int howMany) {
receiveEventcommandReceived = true;
while (Wire.available() > 0)
{
_cmd = Wire.read();
if (_cmd == ArduinoCommand_EpromWrite) {
// Some code
}
else if (_cmd == ArduinoCommand_EpromRead) {
_addr0 = Wire.read();
_addr1 = Wire.read();
_addr = (_addr0 * 256) + _addr1;
_len = Wire.read();
_EEPROMBuffer = NusbioEx.EEPROMRead(_addr, _len);
_r = 128+1;
}
else {
// Some code
}
_count++;
}
}
void requestEvent()
{
requestEventCommandReceived = true;
if (_cmd == ArduinoCommand_EpromRead) {
Wire.write(_EEPROMBuffer, strlen(_EEPROMBuffer));
}
else { // ArduinoCommand_EpromWrite or any other api
int v1 = _r >> 8;
int v2 = _r & 0xFF;
char buffer[2];
buffer[0] = v1;
buffer[1] = v2;
Wire.write(buffer, 2); // MUST BE SENT IN ONE BUFFER -> TO CREATE ONE I2C TRANSACTION
}
}
void SetupI2C() {
Wire.begin(I2C_SLAVE_ADDR); // join i2c bus with address #4
#if I2C_400K
TWBR = 12; // http://www.gammon.com.au/forum/?id=10896
#endif
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
}
void setup() {
SetupI2C();
}
void loop() {
if (requestEventCommandReceived)
{
requestEventCommandReceived = false;
}
#endif
}
I am trying to write an interface for a motorised stage. What I am trying to do is to create a scan feature such that the motor will move a certain distance, stop and wait a specified time and then move the same distance again. It will repeat the process until it has reached the total length specified by the user. To do this I am trying to use a Timer class features as I still want the GUI to be active during the scan.
I've got some idea of how to code it but get stuck. It would go something like:
private void btnGo_Click(object sender, EventArgs e) //On click
{
int i = 0;
int stop = 15; //number of times I want the motor to stop
System.Timers.Timer bTimer; //initialise timer
bTimer = new System.Timers.Timer(waittime); //time I want the motor to wait
bTimer.Elapsed += PerformMove;
bTimer.Enabled = true;
if(i==stop){bTimer.stop()}
}
private void PerformMove(Object source, ElapsedEventArgs e) //event to move motor
{
//movemotor
i++;
}
Not being particularly familiar with C# or timers is undoubtedly the cause of my confusion. What's the best way to approach this problem? Any example code would be great.
If somebody could clarify what the lines
bTimer.Elapsed += PerformMove;
bTimer.Enabled = true;
actually do too that would also be of great use!
EDIT (sorry, didn't think this was a key part): The value of stop is defined upon the user click of the button from a text box within the GUI. i.e.
int stop = Convert.ToDouble(tbIntervalStops.Text); //grab integer from user input upon button click
This would be the correct solution without memory leak
private int i = 0;
private int stop = 15; //number of times I want the motor to stop
private Timer bTimer; //initialise timer -> Thats wrong: nothing is INITIALIZED here its just defined
private void btnGo_Click(object sender, EventArgs e) //On click
{
i = 0;
stop = Convert.ToInt32(tbIntervalStops.Text); //using int because double is a floating point number like 12.34 and for counting only full numbers will be needed
bTimer = new System.Timers.Timer(waittime); //time I want the motor to wait + Here the Timer is INITIALIZED
bTimer.Elapsed += PerformMove; //Adds the Eventhandler, What should be called when the time is over
bTimer.Enabled = true; //This starts the timer. It enables running like pressing the start button on a stopwatch
}
private void PerformMove(Object source, ElapsedEventArgs e) //event to move motor
{
//movemotor
i++;
if (i == stop) //if stop would be a double here we will have the danger to get not a true because of rounding problems
{
bTimer.Stop();
//now enable the Garbage Collector to remove the Timer instance
bTimer.Elapsed -= PerformMove; //This removes the Eventhandler
bTimer.Dispose(); //This frees all resources held by the Timer instance.
bTimer = null;
}
}
Alternatively, you could also derive from the System.Timers.Timer object and create a wrapper which has properties specific to the task. In which case, you would simply need to instantiate a MoveTimer and subscribe to it's OnPerformMoveEvent.
Update: Added OnMovesCompletedEvent
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TimerExample
{
public class MoveTimer : System.Timers.Timer
{
public event EventHandler OnPerformMoveEvent = delegate { };
public event EventHandler OnMovesCompletedEvent = delegate { };
public MoveTimer()
{
Initialize(new TimeSpan(), 0);
}
public MoveTimer(TimeSpan wait, int moves)
{
this.Initialize(wait, moves);
}
private int _i;
private int _totalmoves;
public int Moves
{
get { return this._totalmoves; }
set { this._totalmoves = value; }
}
private TimeSpan _wait;
public TimeSpan Wait
{
get { return this._wait; }
set { this._wait = value; }
}
private System.Timers.Timer _timer;
private void Initialize(TimeSpan wait, int moves)
{
this._totalmoves = moves;
this._wait = wait;
this._timer = new System.Timers.Timer(wait.Milliseconds);
}
private void BindComponents()
{
this._timer.Elapsed += _timer_Elapsed;
}
private void UnBindComponents()
{
this._timer.Elapsed -= _timer_Elapsed;
}
public void StartTimer()
{
this._timer.Enabled = true;
}
public void StopTimer()
{
this._timer.Enabled = false;
}
void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
this._i++;
if (this.OnPerformMoveEvent != null)
this.OnPerformMoveEvent(this, EventArgs.Empty);
if (this._i == this._totalmoves)
{
this._timer.Stop();
this.UnBindComponents();
this.Dispose();
if (this.OnMovesCompletedEvent != null)
this.OnMovesCompletedEvent(this, EventArgs.Empty);
}
}
}
}
In regards to the user input where the number of moves or stops is provided as a string. I would handle this outside of the MoveTimer object. Validation should always be performed.
First determine that the value can be parsed into an integer. If not, throw an exception to let the user know that the input was entered incorrectly.
To use the above, something like the following would be all it requires:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TimerExample
{
class Program
{
static void Main(string[] args)
{
//Create move timer that will trigger 15 times, once every 30 seconds.
MoveTimer moveTimer = new MoveTimer(new TimeSpan(0, 0, 30), 15);
//Substribe to the move timer events
moveTimer.OnPerformMoveEvent += moveTimer_OnPerformMoveEvent;
moveTimer.OnMovesCompletedEvent += moveTimer_OnMovesCompletedEvent;
//Start the timer
moveTimer.StartTimer();
//What happens in between the moves performed?
}
static void moveTimer_OnMovesCompletedEvent(object sender, EventArgs e)
{
//All the moves have been performed, what would you like to happen? Eg. Beep or tell the user.
}
static void moveTimer_OnPerformMoveEvent(object sender, EventArgs e)
{
//Timer has lapsed, what needs to be done when a move is requested?
}
}
}