So i'm in a bit of a problem, i'm coding a clap sensor, that hears when someone claps and executes a certain command.
//CLAP
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private void button1_Loaded(object sender, RoutedEventArgs e)
{
if (Convert.ToInt16(textBox1.Text) > 100)
{
MessageBox.Show("Invalid Value");
return;
}
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for ( int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
}
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
}
//CLAP
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
for (int index = 0; index < e.BytesRecorded; index += 2)
{
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
{
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
{
waveIn.StopRecording();
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Did you Clap?");
}
}
}
}
The code itself works as is, but I need it to be able to reset itself as many times as I need. This program basically listens for a clap and wakes up the monitor and starts it up. The program breaks any time I add in another "waveIn.StartRecording();"
Any ideas on how I could refresh the page or make it listen for ever?
What basically your code is doing is opening waveIn to receive audio data, then examining the data for loud samples. When it receives a sample that exceeds a threshold it then stops listening and issues the command.
As written, the code stops after the first large sample is detected. No more audio data is received, etc. Probably not what you want. Instead you need to refine your clap detection so that it will stop processing the incoming data for a period of time - a few seconds say - after it detects the first big sample. Don't stop receiving the audio data, just stop reacting to it.
Add a DataTime field to your class that records the timestamp of the last clap detection. At the start of your waveIn_DataAvailable method check if the elapsed time since the last detection is less than your silence time, and if so just return without processing the audio block. When you detect a large enough sample, fire off the event and update the last clap detection field.
Something like this:
DateTime LastDetection = DateTime.Now.AddMinutes(-1);
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
if (LastDetection.AddSeconds(3) >= DateTime.Now)
return;
if (DetectClap(e.Buffer))
{
LastDetection = DateTime.Now;
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Clap detected.");
}
}
bool DetectClap(byte[] audiobytes)
{
for (int i = 0; i < audiobytes.Length; i += 2)
{
float sample32 = (float)((short)((audiobytes[0] << 8) | audiobytes[1]))/32768f;
if (sample32 > MaxValue)
return true;
}
return false;
}
Here is an example that moves the WaveIn logic to a background thread. It should give you enough to start. Please check the documentation for a complete example that includes the background thread cancellation.
//CLAP
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private BackgroundWorker worker;
private void button1_Loaded(object sender, RoutedEventArgs e)
{
if (Convert.ToInt16(textBox1.Text) > 100)
{
MessageBox.Show("Invalid Value");
return;
}
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
// You'll need to handle the thread cancellation
// when the user clicks the button again
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += (s, e) =>
{
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for ( int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
}
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
};
worker.ProgressChanged += (s, e) =>
{
SendMessage(MONITOR_ON, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_ON);
MessageBox.Show("Did you Clap?");
};
worker.RunWorkerAsync();
}
//CLAP
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
for (int index = 0; index < e.BytesRecorded; index += 2)
{
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
{
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
{
worker.ReportProgress(0);
break;
}
}
}
}
So in the end I went with a different way than both suggested answers.
private float bigValue;
WaveIn waveIn;
private double MaxValue;
private void button1_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (Convert.ToInt16(textBox1.Text) > 100)
{
MessageBox.Show("Invalid Value");
return;
}
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
//Get Device Count
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
}
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
}
private void button1_Loaded(object sender, RoutedEventArgs e)
{
if (Convert.ToInt16(textBox1.Text) > 100)
{
MessageBox.Show("Invalid Value");
return;
}
else
MaxValue = Convert.ToDouble(textBox1.Text) / 100;
bigValue = 0;
waveIn = new WaveIn();
int waveInDevices = waveIn.DeviceNumber;
for (int i = 0; i <= 100; i++)
{
}
//Get Device Count
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
{
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
}
waveIn.DeviceNumber = 0;
waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
int sampleRate = 8000;
int channels = 1;
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
}
int i = 0;
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
{
for (int index = 0; index < e.BytesRecorded; index += 2)
{
short sample = (short)((e.Buffer[index + 1] << 8) | e.Buffer[index + 0]);
float sample32 = sample / 32768f;
label1.Content = sample32.ToString();
if (bigValue < sample32)
{
bigValue = sample32;
label2.Content = bigValue.ToString();
if (bigValue > MaxValue)
{
waveIn.StopRecording();
if (IsOdd(i))
{
button1.IsEnabled = false;
}
else
{
button1.IsEnabled = true;
}
MessageBox.Show("Did you Clap?");
i++;
}
}
}
}
public static bool IsOdd(int value)
{
return value % 2 != 0;
}
}
The first load event sets it off. The second one goes back in forth between button on and button off using the IsEnabled event. The on and off are acheived by and if statement choosing between an odd number and even.
That is how I achieved this infinite loop.
NOTE: This way probably isn't the most efficient way but it got the job done.
Also I left the (Open Window) code out of this answer.
Related
I am learning C #, and I am creating a hypothetical game for me to understand the language. I want several bots to follow the Player who is moving the rectangle, but I can only move the player, but the automatic bots do not move.
I really researched what I could do to move these bots. And I came to the conclusion that I would have to understand Threads, which simply causes the program not to crash.
I leave here the full code of what I am trying.
public partial class Form1 : Form
{
public enum Direction { Up, Down, Left, Right }
private Player player;
private List<Bot> bots;
public Form1()
{
InitializeComponent();
this.Paint += Form1_Paint;
this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
this.player = new Player(new Size(8, 8));
this.bots = new List<Bot>();
for (int i = 0; i < 30; i++)
{
Bot bot = new Bot(player, new Size(8, 8));
bot.Follow();
this.bots.Add(bot);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
player.Move(Direction.Up);
break;
case Keys.Down:
player.Move(Direction.Down);
break;
case Keys.Left:
player.Move(Direction.Left);
break;
case Keys.Right:
player.Move(Direction.Right);
break;
}
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
List<Rectangle> rs = new List<Rectangle>();
rs = this.bots.Select(x => x.Rectangle).ToList();
rs.Add(player.Rectangle);
if (rs.Count > 0)
{
e.Graphics.FillRectangles(new SolidBrush(Color.Red), rs.ToArray());
}
}
}
public class Player
{
private Rectangle rectangle;
public Rectangle Rectangle { get => rectangle; }
public Player(Size size)
{
this.rectangle = new Rectangle() { Size = size };
}
public void Move(Direction direction)
{
switch (direction)
{
case Direction.Up:
this.rectangle.Y -= 3;
break;
case Direction.Down:
this.rectangle.Y += 3;
break;
case Direction.Left:
this.rectangle.X -= 3;
break;
case Direction.Right:
this.rectangle.X += 3;
break;
default:
break;
}
}
}
public class Bot
{
private Rectangle rectangle;
private Player player;
public Rectangle Rectangle { get => rectangle; }
public Bot(Player player, Size size)
{
this.player = player;
this.rectangle = new Rectangle() { Size = size };
}
public void Follow()
{
Task.Run(() =>
{
while (true)
{
Point p = player.Rectangle.Location;
Point bot = rectangle.Location;
for (int i = bot.X; i < p.X; i += 2)
{
Thread.Sleep(100);
bot.X = i;
}
for (int i = bot.X; i > p.X; i -= 2)
{
Thread.Sleep(100);
bot.X = i;
}
for (int i = bot.Y; i < p.Y; i += 2)
{
Thread.Sleep(100);
bot.Y = i;
}
for (int i = bot.Y; i > p.Y; i -= 2)
{
Thread.Sleep(100);
bot.Y = i;
}
}
});
}
}
As you can see, I can only move the player, but the bots don't move what can I do to move the bots?
I think a Timer would work better here and remove the requirement for you to fully understanding threading at this point, as it will handle the details for you. I'm assuming you actually want the bots to "follow" instead of only moving when the Player moves and will fall behind if the player is moving quickly.
So to use a Timer, I would adjust your Bot class as below, to remove your usage of threads and only allow it to take a single step towards the player in the Follow method which will be called every 100ms. Note Rectangle is a struct, so it is not mutable - that is why your bots do not move - if you do the following:
Point bot = Rectangle.Location;
bot.X = 5;
You're probably thinking Rectangle.Location.X is now 5; but it is not. So we create a new rectangle using the new position.
public class Bot
{
private Player player;
public Rectangle Rectangle { get; set; }
public Bot(Player player, Size size)
{
this.player = player;
this.Rectangle = new Rectangle() { Size = size };
}
public void Follow()
{
Point p = player.Rectangle.Location;
Point bot = Rectangle.Location;
for (int i = bot.X + 2; i < p.X;)
{
bot.X = i;
break;
}
for (int i = bot.X - 2; i > p.X;)
{
bot.X = i;
break;
}
for (int i = bot.Y + 2; i < p.Y;)
{
bot.Y = i;
break;
}
for (int i = bot.Y - 2; i > p.Y;)
{
bot.Y = i;
break;
}
Rectangle = new Rectangle(bot, player.Rectangle.Size);
}
}
And add the following code to replace your existing constructor and add another method to handle the Timer tick.
private Timer timer;
public Form1()
{
InitializeComponent();
this.Paint += Form1_Paint;
this.KeyPreview = true;
this.KeyDown += Form1_KeyDown;
// setup a timer which will call Timer_Tick every 100ms
timer = new System.Windows.Forms.Timer();
timer.Interval = 100;
timer.Tick += Timer_Tick;
timer.Start();
this.player = new Player(new Size(8, 8));
this.bots = new List<Bot>();
for (int i = 0; i < 30; i++)
{
Bot bot = new Bot(player, new Size(8, 8));
bot.Follow();
this.bots.Add(bot);
}
}
private void Timer_Tick(object sender, System.EventArgs e)
{
foreach (var bot in bots)
bot.Follow();
this.Invalidate();
}
Point is a value type (a struct). (Read more about this at What's the difference between struct and class in .NET?)
When you did this:
Point bot = Rectangle.Location;
bot.X = i;
...you created a local Point and modified it. This doesn't change the Location of the Rectangle of the Bot. Also, Rectangles are structs too, so you have to modify the original Bot's Rectangle, or assign a new Rectangle to the Bot.
To fix, you could replace:
bot.X = i;
...with...
this.rectangle.X = i;
And make the similar change for .Y (in all your for loop locations)
Spelling it all out:
public void Follow()
{
Task.Run(() =>
{
while (true) {
Point p = player.Rectangle.Location;
Point bot = rectangle.Location;
for (int i = bot.X; i < p.X; i += 2) {
Thread.Sleep(100);
this.rectangle.X = i;
}
for (int i = bot.X; i > p.X; i -= 2) {
Thread.Sleep(100);
this.rectangle.X = i;
}
for (int i = bot.Y; i < p.Y; i += 2) {
Thread.Sleep(100);
this.rectangle.Y = i;
}
for (int i = bot.Y; i > p.Y; i -= 2) {
Thread.Sleep(100);
this.rectangle.Y = i;
}
}
});
}
I am new in C# and trying to create zedgraph of lessor sensor.
First I create a global variable and write code for graph. My graph is working but after reached to the point of 100 of x axis it will overlap to old line. z1.GraphPane.CurveList.Clear(); command is not working. I tried listPointsOne.clear(); command also but that clear the line and doesn't show anything on graph. Please help me out with this.
My code is below :
string DatafromCOM;
double[] x = new double[100];
double[] y = new double[100];
int i;
PointPairList listPointsOne = new PointPairList();
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
while (serialPort1.BytesToRead > 0)
{
DatafromCOM = serialPort1.ReadLine();
double iData;
var ok = double.TryParse(txtKQ.Text, out iData);
if (DatafromCOM.Trim() != "" && ok)
{
i= (i + 1) % 100;
x[i] = i;
y[i] = iData;
listPointsOne.Add(i,iData);
}
}
}
catch { }
}
private void timer1_Tick(object sender, EventArgs e)
{
z1.GraphPane.CurveList.Clear();
z1.GraphPane.AddCurve(null, listPointsOne, Color.Red, SymbolType.None);
z1.AxisChange();
z1.Invalidate();
}
You should clear the curvlist
string DatafromCOM;
double[] x = new double[100];
double[] y = new double[100];
int i;
PointPairList listPointsOne = new PointPairList();
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
try
{
while (serialPort1.BytesToRead > 0)
{
DatafromCOM = serialPort1.ReadLine();
double iData;
var ok = double.TryParse(txtKQ.Text, out iData);
if (DatafromCOM.Trim() != "" && ok)
{
i= (i + 1) % 100;
x[i] = i;
y[i] = iData;
listPointsOne.Add(i,iData);
}
z1.GraphPane.CurveList.Clear(); // Change here
}
}
catch { }
}
private void timer1_Tick(object sender, EventArgs e)
{
z1.GraphPane.AddCurve(null, listPointsOne, Color.Red, SymbolType.None);
z1.AxisChange();
z1.Invalidate();
}
I'm using GestureDetector.SimpleOnGestureListener class for handling some simple gestures on my app. And it's works perfectly.
But now I'm faced with a problem of handling multiple tap gesture.
I Just want to configure NumbersOfTaps and handle appropriate gesture.
But can't find any details or notes How to implement it on Andoid or Xamarin.Android documentation.
DateTime _firstTap;
int _tapCount = 0;
const int TAP_COUNT_TRESHOLD = 5; //number of taps
const int TIME_TRESHOLD 200; //ms time
protected override void OnResume()
{
myButton.Clicked += ButtonTapped;
}
protected override void OnPause()
{
myButton.Clicked -= ButtonTapped;
}
void ButtonTapped(object sender, EventArgs e){
var time = Math.Round((DateTime.Now - _firstTap).TotalMilliseconds, MidpointRounding.AwayFromZero);
if (time > TIME_TRESHOLD)
{
_tapCount = 1;
_firstTap = DateTime.Now;
}
else
_tapCount++;
if (_tapCount == TAP_COUNT_TRESHOLD)
{
//do your logic here
}
}
Time limit and number of clicks are configurable.
Use that code, I do not believe if it is good approach but it works. Check it out.
long milliSeconds = 0;
var tapCount = 0;
var millisecondsPeriod = 200;
button.Click += (object sender, EventArgs e) => {
if (milliSeconds == 0) {
milliSeconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
tapCount++;
} else {
var currMill = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond - milliSeconds;
if (currMill < millisecondsPeriod) {
milliSeconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
tapCount++;
if (tapCount == 3) {
Toast.MakeText (this, "triple", ToastLength.Long).Show ();
}
} else {
tapCount = 0;
milliSeconds = 0;
}
}
};
You can change the millisecondsPeriod how you wish.
Problem
I'm using a C# application to record keyboard and mouse movement, processing that movement and sending serial data out to a micro-controller that interpreters that data and moves a set of servos. In the past I had created a box or image that was the resolution(number of steps) my servos were capable of, clipped the mouse to that box or image, and processed where the cursor was in that box and sent data to my servos to move to that position.
This worked fine and dandy till I needed to move a greater amount of steps than my monitor has resolution.
So my question is what options are available to me for tracking mouse movement up to 10,000 steps/resolution in the X and Y axis?
Possible solution route
Thinking outside the box I think I could hide and center the mouse on the screen, record how much the mouse moved on mousemoved events, process that data, then recenter the mouse on the screen to give me unlimited movement in each axis.
Enclosed below is my PIC18F2420 code. Currently it is fed x and y positions via serial communications from my C# application. Data is stored in a ring buffer as it is received and processed as soon as possible.
PIC CODE
#include <p18f2420.h>
#include <cType.h>
#include <usart.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <timers.h>
#include <delays.h>
/**********************************************************************************************/
//DEFINES
#define switch_0 PORTCbits.RC4
#define switch_1 PORTCbits.RC5
#define bufferSize 48
/**********************************************************************************************/
/**********************************************************************************************/
//Function prototypes
void high_isr(void);
void int2ASCII(unsigned int output);
void UART_putChar(unsigned char value);
char readBuffer();
char emptyBuffer();
char peekBuffer();
void limitServo0(); //limit movement via predetermined min/max
void limitServo1();
/**********************************************************************************************/
unsigned char hertz = 75; //value to generate 5-=60 hertz wave default value 75
unsigned int timer0, servo0Min, servo0Max;
unsigned int timer1, servo1Min, servo1Max;
unsigned char servo0Rate = 10;
unsigned char ByteOut;
char array[bufferSize]; //input rs-232 buffer
char valueArray[bufferSize];
char dataArray[bufferSize];
char tempArray[bufferSize];
unsigned char tempIndex;
unsigned char head = 0;
unsigned char tail = 0;
//variables used to disect the comma delimited string
char CVdata; //do we have a command and value?
char CVvalue; //bool value like above
//BOOLEAN IF values
/**********************************************************************************************/
//Interrupt Service Routine
#pragma code high_vector=0x08
void interrupt_at_high_vector (void)
{
_asm GOTO high_isr _endasm
}
#pragma code /* return to the default code section */
#pragma interrupt high_isr
void high_isr (void)
{
if(PIR1bits.TMR2IF == 1)
{
//T0CONbits.TMR0ON = 0;
//T1CONbits.TMR1ON = 0;
INTCONbits.TMR0IF = 0; //Turn off Int Flag
PIR1bits.TMR1IF = 0;
PIR1bits.TMR2IF = 0; //Turn off Int Flag
LATCbits.LATC3 = 1; //Turn on data line
TMR0H = timer0/256; //Extract HIGH byte always do Hbyte first
TMR0L = timer0; //Extract LOW byte
}
if(PIR1bits.TMR1IF == 1)
{
PIR1bits.TMR1IF = 0;
//T1CONbits.TMR1ON = 0;
//PIR1bits.TMR2IF = 0; //Turn off Int Flag
INTCONbits.TMR0IF = 0; //Turn off Int Flag
LATCbits.LATC2 = 0;
PR2 = hertz; //Generate 50-60hertz pulse
}
if(INTCONbits.TMR0IF == 1)
{
LATCbits.LATC2 = 1;
//PIR1bits.TMR1IF = 0;
//PIR1bits.TMR2IF = 0; //Turn off Int Flag
//T0CONbits.TMR0ON = 0;
//T1CONbits.TMR1ON = 1;
INTCONbits.TMR0IF = 0; //Turn off Int Flag
LATCbits.LATC3 = 0;
TMR1H = timer1/256;
TMR1L = timer1;
}
if(PIR1bits.RCIF == 1)
{
PIR1bits.RCIF = 0;
array[tail] = RCREG;
//array[tail] = ReadUSART();
tail++;
if(tail == bufferSize)
{
tail = 0;
}
/* Clear the interrupt flag */
}
}
/**********************************************************************************************/
void main(void)
{
/**********************************************************************************************/
//Initialize
memset(array, '\0' , bufferSize);
memset(tempArray, '\0' , bufferSize);
memset(dataArray, '\0' , bufferSize);
memset(valueArray, '\0' , bufferSize);
TRISC = 0b10110000;//RC4 and RC5 inputs for switches
servo0Max = 65000; //Max value allowed PAN 65000
servo0Min = 62000; //Min value allowed 63500
servo1Max = 65000; //Tilt 64138
servo1Min = 62000; //TILT 63864
timer0 = 64250; //Initial position
timer1 = 64200;
CVdata = 0;
CVvalue = 0;
tempIndex = 0;
LATCbits.LATC0 = 0;
/**********************************************************************************************/
//USART
OpenUSART(USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_CONT_RX &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_BRGH_HIGH
, 16);//change back to 16 for 57.6 103 for 9.6
RCSTAbits.ADDEN = 0;//Testing this out might not help with overflow
TXSTAbits.SYNC = 0;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
TXSTAbits.BRGH = 1;
BAUDCONbits.BRG16 = 1;
/**********************************************************************************************/
//Initialize Timer0
OpenTimer0(TIMER_INT_ON &
T0_SOURCE_INT &
T0_16BIT);
T0CONbits.PSA = 1;
INTCONbits.TMR0IF = 0;
/**********************************************************************************************/
/**********************************************************************************************/
//Initialize Timer1
OpenTimer1(TIMER_INT_ON &
T1_16BIT_RW &
T1_SOURCE_INT &
T1_PS_1_1);
T1CONbits.T1CKPS1 = 0; // bits 5-4 Prescaler Rate Select bits
T1CONbits.T1CKPS0 = 0; // bit 4
T1CONbits.T1OSCEN = 1; // bit 3 Timer1 Oscillator Enable Control bit 1 = on
T1CONbits.T1SYNC = 1; // bit 2 Timer1 External Clock Input Synchronization Control bit...1 = Do not synchronize external clock input
T1CONbits.TMR1CS = 0; // bit 1 Timer1 Clock Source Select bit...0 = Internal clock (FOSC/4)
T1CONbits.TMR1ON = 1; // bit 0 enables timer
/**********************************************************************************************/
/**********************************************************************************************/
//Initialize Timer2
OpenTimer2( TIMER_INT_ON &
T2_PS_1_16 &
T2_POST_1_16);
PR2 = hertz;
PIE1bits.TMR2IE = 1;
IPR1bits.TMR2IP = 1;
INTCONbits.GIEH = 1; //enable global interrupts
INTCONbits.GIEL = 1;
/**********************************************************************************************/
while(1)
{
while(emptyBuffer());
if(CVdata == 0 && CVvalue == 1)
{
//ERROR THIS SHOULDN't HAPPEN! FLUSH BUFFER
CVdata = 0;
CVvalue = 0;
}
if(CVdata == 0 && CVvalue == 0)
{
if(peekBuffer() != ',')
{
tempArray[tempIndex] = readBuffer();
tempIndex++;
}
else
{
readBuffer();//if comma sent first read it and throw away
if(tempIndex > 0) //comma read and data in buffer
{
memcpy(dataArray, tempArray, tempIndex);
tempIndex = 0;
CVdata = 1;
memset(tempArray, 'a' , bufferSize);
}
}
}
if(CVdata ==1 && CVvalue == 0)
{
if(peekBuffer() != ',')
{
if(isdigit(peekBuffer()))
{
tempArray[tempIndex] = readBuffer();
tempIndex++;
}
else
readBuffer();
}
else
{
//readBuffer();
if(tempIndex > 0)
{
memcpy(valueArray, tempArray, tempIndex);
tempIndex = 0;
CVvalue = 1;
memset(tempArray, 'a', bufferSize);
}
}
}
if(CVdata == 1 && CVvalue == 1)
{
switch(dataArray[0])
{
case 'x':
case 'X':
{
//timer0 = current = atof(valueArray);//ISSUE HERE first char null
timer0 = (unsigned int)atoi(valueArray);
break;
}
case 'y':
case 'Y':
{
timer1 = (unsigned int)atoi(valueArray);
break;
}
}
CVdata = 0;
CVvalue = 0;
memset(dataArray, 'a' , bufferSize);
memset(valueArray, 'a' , bufferSize);
}
limitServo0();
limitServo1();
}
}
/**********************************************************************************************/
//Functions
void int2ASCII(unsigned int output)
{
unsigned char digit = 0;
while (output >= 10000) { output -= 10000; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 1000) { output -= 1000; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 100) { output -= 100; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 10) { output -= 10; digit++; } UART_putChar(digit + 0x30); digit = 0;
while (output >= 1) { output -= 1; digit++; } UART_putChar(digit + 0x30);
}
void UART_putChar(unsigned char value)
{
while(PIR1bits.TXIF == 0);
TXREG = value;
}
char readBuffer()
{
if(tail != head)
{
ByteOut = array[head];
head++;
if(head == bufferSize)
{
head = 0;
}
return ByteOut;
}
//LATCbits.LATC0 = 1;
}
char peekBuffer()
{
return array[head];
}
char emptyBuffer()
{
if(tail == head)
return 1;
else
return 0;
}
void limitServo0()
{
if(timer0 > servo0Max)
{
timer0 = servo0Max;
}
if(timer0 < servo0Min)
{
timer0 = servo0Min;
}
}
void limitServo1()
{
if(timer1 > servo1Max)
{
timer1 = servo1Max;
}
if(timer1 < servo1Min)
{
timer1 = servo1Min;
}
}
An Example of my previous tracking via bitmap can be viewed on my youtube channel at: http://www.youtube.com/watch?v=rBhkV3dnyiU&list=UULGlw5rGZfETaiPs49JBEuA&index=41
UPDATE
After some research it seems I can write a XNA application, capture mouse movement, and output serial communications. I would really really like a windows forms solution but I do have XNA experience so guess I'll work on converting my application until another solution presents itself.
My initial purposed solution did the trick. On trackingEnabled I center the mouse and check how much it has moved every 100ms, after that I recenter it and send the data to my controller.
using System;
using System.Timers;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using PIC18F_Servo_Control_V2;
namespace FSI_Grid1
{
public partial class Form1 : Form
{
TabControl LeftControlTab;
System.Timers.Timer myTimer;
public delegate void UpdateStatusBarDelegate();
TabPage myTabPage;
Grid myGrid;
serialConnection myConnection;
int timerDelay = 100;
int initialX, initialY, currentX, currentY, minX, minY, maxX, maxY;
int MouseCurrentX, MouseCurrentY, MouseMovedX, MouseMovedY;//tracking mousemovement
int offsetX, offsetY;//how much each arrow click moves the servos
bool trackingActive;//are we in tracking mode?
bool MouseMovedFlag;
int YOffsetValue;//used to offset dynamically generated buttons in tab groups
int XCenter, YCenter;
enum States { Startup, MouseTracking, KeyboardTracking, Script, Idle };//state engine
States CurrentState;
public Form1()
{
currentX = initialX = 63503;
currentY = initialY = 64012;
minX = 62000;
maxX = 65000;
minY = 62000;
maxY = 65000;
offsetX = 10;
offsetY = 10;
trackingActive = false;
YOffsetValue = 0;
CurrentState = States.Startup;
MouseMovedFlag = false;
myTimer = new System.Timers.Timer(timerDelay);
myTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
myTimer.Elapsed += new ElapsedEventHandler(TrackMouse);
myTimer.Enabled = false;
InitializeComponent();
InitializeGrid();
InitializeLeftControlTab();
InitializeSerial();
//Initialize StatusBar
RadioButton button = (RadioButton)this.Controls.Find("SelectKeyboardRadioButton", true)[0];
button.Checked = true;
activeStatus.Text = "Keyboard Tracking DEACTIVATED";
activeStatus.BackColor = Color.Red;
ConnectionStatus.Text = "Disconnected!";
xOffsetStatus.Text = "X offset value " + offsetX.ToString();
yOffsetStatus.Text = "Y offset value " + offsetY.ToString();
//this.MouseMove += new MouseEventHandler(Form_MouseMove);
XCenter = this.Location.X + this.Width / 2;
YCenter = this.Location.Y + this.Height / 2;
}
~Form1()
{
if (myConnection.connected)
myConnection.disconnect();
}
private void widthTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
private void widthTextBox_KeyUp(object sender, KeyEventArgs e)
{
TextBox text = (TextBox)this.Controls.Find("widthTextBox", true)[0];
xOffsetStatus.Text = text.Text;
offsetX = Convert.ToInt16(text.Text);
}
private void heightTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = !char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar);
}
private void heightTextBox_KeyUp(object sender, KeyEventArgs e)
{
TextBox text = (TextBox)this.Controls.Find("heightTextBox", true)[0];
yOffsetStatus.Text = text.Text;
offsetY = Convert.ToInt16(text.Text);
}
private void LeftControlTab_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _textBrush;
// Get the item from the collection.
TabPage _tabPage = LeftControlTab.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _tabBounds = LeftControlTab.GetTabRect(e.Index);
if (e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_textBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.White, e.Bounds);
}
else
{
_textBrush = new System.Drawing.SolidBrush(e.ForeColor);
g.FillRectangle(Brushes.LightGray, e.Bounds);
//e.DrawBackground();
}
// Use our own font.
Font _tabFont = new Font("Arial", (float)10.0, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _stringFlags = new StringFormat();
_stringFlags.Alignment = StringAlignment.Center;
_stringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_tabPage.Text, _tabFont, _textBrush, _tabBounds, new StringFormat(_stringFlags));
}
private void InitializeLeftControlTab()
{
LeftControlTab = new TabControl();
LeftControlTab.Location = new Point(10, 30);
LeftControlTab.Size = new Size(300, 500);
LeftControlTab.Alignment = TabAlignment.Left;
LeftControlTab.SizeMode = TabSizeMode.Fixed;
LeftControlTab.ItemSize = new Size(30, 90);
LeftControlTab.DrawMode = TabDrawMode.OwnerDrawFixed;
/*EVENT HANDLER*/
LeftControlTab.DrawItem += new DrawItemEventHandler(LeftControlTab_DrawItem);
/*TABS*/
int offset = 100; //how far to the right the edit boxes are
myTabPage = new TabPage();
myTabPage.Text = "Appearance";
LeftControlTab.Controls.Add(myTabPage);
myTabPage = new TabPage();
myTabPage.Text = "Settings";
/*LABEL*/
Label OffsetLabel = new Label();
OffsetLabel.Text = "Step resolution";
OffsetLabel.Location = new Point(0,YOffset());
myTabPage.Controls.Add(OffsetLabel);
/*WIDTH LABEL*/
Label widthLabel = new Label();
widthLabel.Text = "Width";
widthLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(widthLabel);
/*WIDTH TEXTBOX*/
TextBox widthTextBox = new TextBox();
widthTextBox.Name = "widthTextBox";
widthTextBox.Text = myGrid.Width.ToString();
widthTextBox.Location = new Point(widthLabel.Location.X + offset, widthLabel.Location.Y);
myTabPage.Controls.Add(widthTextBox);
widthTextBox.KeyPress += new KeyPressEventHandler(widthTextBox_KeyPress); //EVENT HANDLER
widthTextBox.KeyUp += new KeyEventHandler(widthTextBox_KeyUp); //EVENT HANDLER
/*HEIGHT LABEL*/
Label heightLabel = new Label();
heightLabel.Text = "Height";
heightLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(heightLabel);
/*HEIGHT TEXTBOX*/
TextBox heightTextBox = new TextBox();
heightTextBox.Name = "heightTextBox";
heightTextBox.Text = myGrid.Height.ToString();
heightTextBox.Location = new Point(heightLabel.Location.X + offset, heightLabel.Location.Y);
myTabPage.Controls.Add(heightTextBox);
/*RADIOBUTTON LABEL*/
GroupBox RadioLabel = new GroupBox();
RadioLabel.Text = "Tracking Style";
RadioLabel.Location = new Point(0, YOffset());
myTabPage.Controls.Add(RadioLabel);
/*RADIO BUTTONS*/
RadioButton SelectMouse = new RadioButton();
SelectMouse.Location = new Point(10, 20);
SelectMouse.Text = "Mouse";
SelectMouse.Name = "SelectMouseRadioButton";
SelectMouse.CheckedChanged += new EventHandler(RadioButtons_CheckedChanged);
RadioLabel.Controls.Add(SelectMouse);
RadioButton SelectKeyboard = new RadioButton();
SelectKeyboard.Location = new Point(10, 42);
SelectKeyboard.Text = "Keyboard";
SelectKeyboard.Name = "SelectKeyboardRadioButton";
SelectKeyboard.CheckedChanged += new EventHandler(RadioButtons_CheckedChanged);
RadioLabel.Controls.Add(SelectKeyboard);
heightTextBox.KeyPress += new KeyPressEventHandler(heightTextBox_KeyPress); //EVENT HANDLER
heightTextBox.KeyUp += new KeyEventHandler(heightTextBox_KeyUp); //EVENT HANDLER
//EVENT HANDLER
LeftControlTab.Controls.Add(myTabPage);
Controls.Add(LeftControlTab);
}
private void InitializeGrid()
{
myGrid = new Grid(offsetX, offsetY);
}
private void connectToolStripMenuItem_Click(object sender, EventArgs e)
{
serialConnectionDialogBox serialBox = new serialConnectionDialogBox();
Point temp = this.Location;
temp.X += 30;
temp.Y += 70;
serialBox.Location = temp;
DialogResult results = serialBox.ShowDialog();
if (results == DialogResult.Yes && !myConnection.connected)
{
myConnection.setCOMMPort(serialBox.commPortComboBox.Text);
myConnection.setBaudRate(Convert.ToInt32(serialBox.baudRateComboBox.Text));
myConnection.connect();
}
if (myConnection.connected)
{
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
}
}
private void InitializeSerial()
{
myConnection = new serialConnection();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
bool updatePos = false;
switch (keyData)
{
case Keys.Left:
currentX += offsetX;
updatePos = true;
break;
case Keys.Right:
currentX -= offsetX;
updatePos = true;
break;
case Keys.Up:
currentY += offsetY;
updatePos = true;
break;
case Keys.Down:
currentY -= offsetY;
updatePos = true;
break;
case Keys.F5:
if (trackingActive)
{
trackingActive = false;
LeftControlTab.Enabled = true;
if(CurrentState == States.KeyboardTracking)
activeStatus.Text = "Keyboard Tracking DEACTIVATED";
if (CurrentState == States.MouseTracking)
activeStatus.Text = "Mouse Tracking DEACTIVATED";
activeStatus.BackColor = Color.Red;
myTimer.Enabled = false;
}
else
{
trackingActive = true;
LeftControlTab.Enabled = false;
if (CurrentState == States.KeyboardTracking)
activeStatus.Text = "Keyboard Tracking ACTIVATED";
if (CurrentState == States.MouseTracking)
activeStatus.Text = "Mouse Tracking ACTIVATED";
activeStatus.BackColor = Color.Green;
myTimer.Enabled = true;
}
break;
}
if (updatePos == true)
{
updatePos = false;
Point temp = new Point();
temp.X = currentX = clipX(currentX);
temp.Y = currentY = clipY(currentY);
String tx = "x," + Convert.ToString(temp.X) + ",y," + Convert.ToString(temp.Y) + ",";
myConnection.sendData(tx);
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
}
return base.ProcessCmdKey(ref msg, keyData);
}
private void disconnectToolStripMenuItem_Click_1(object sender, EventArgs e)
{
if (myConnection.connected)
{
myConnection.disconnect();
ConnectionStatus.Text = "Disconnected!";
}
}
private void RadioButtons_CheckedChanged(object sender, EventArgs e)
{
if (sender == (RadioButton)this.Controls.Find("SelectMouseRadioButton", true)[0])
{
CurrentState = States.MouseTracking;
activeStatus.Text = "Mouse Tracking ";
}
if (sender == (RadioButton)this.Controls.Find("SelectKeyboardRadioButton", true)[0])
{
CurrentState = States.KeyboardTracking;
activeStatus.Text = "Keyboard Tracking ";
}
if (trackingActive)
activeStatus.Text += "ACTIVATED";
else
activeStatus.Text += "DEACTIVATED";
}
private void TrackMouse(object source, ElapsedEventArgs e)
{
if (trackingActive && CurrentState == States.MouseTracking)
{
MouseMovedFlag = true;
MouseMovedX = -1 * (Cursor.Position.X - XCenter);
MouseMovedY = -1 * (Cursor.Position.Y - YCenter);
currentX += MouseMovedX;
currentX = clipX(currentX);
currentY += MouseMovedY;
currentY = clipY(currentY);
statusStrip1.Invoke(new UpdateStatusBarDelegate(this.UpdateStatusBar), null);
Cursor.Position = new Point(XCenter, YCenter);
}
}
private int clipX(int tempX)
{
if(tempX < minX)
tempX = minX;
if(tempX > maxX)
tempX = maxX;
return tempX;
}
private int clipY(int tempY)
{
if(tempY < minY)
tempY = minY;
if (tempY > maxY)
tempY = maxY;
return tempY;
}
private int YOffset()
{
int tempValue = YOffsetValue;
if (tempValue == 0)
{
YOffsetValue += 22;
return tempValue;
}
else
{
YOffsetValue += 22;
return tempValue;
}
}
void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (true)
{
if (MouseMovedFlag || trackingActive)
{
Point temp = new Point();
temp.X = currentX;
temp.Y = currentY;
String tx = "x," + Convert.ToString(temp.X) + ",y," + Convert.ToString(temp.Y) + ",";
myConnection.sendData(tx);
}
}
}
void UpdateStatusBar()
{
ConnectionStatus.Text = "X " + currentX.ToString() + "Y " + currentY.ToString();
ConnectionStatus.Invalidate();
this.Update();
}
}
}
Started learning to code.
Have a console writing a 10 by ten grid of numbers randomly increasing in value.
Tried to do same in a form (DataGridView).
It works fine but there is no window until calcs are finished (I had to put a limit in - instead of an infinite loop).
I came here and read about refresh and doevent - but they dramatically slow everything down. But at least I can see the calcs happening.
I've tried to get my head around backgroundworker and I'm afraid I can't. If I'm in a loop to calculate - how do I separate those calcs from a screen update.
EDIT : Followed Nico's help(Thanks!!) and got this. Much better, but still laggy with big numbers. But a rocket with small numbers.
Any help to make faster?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace stackoverflowTest
{
public partial class Form1 : Form
{
Random rnd = new Random((Int32)DateTime.Now.Ticks);
private static int numSides = 8;
int numDice=2;
private int numRolls = 100000000;
private int max = 1;
private int min = 0;
private int diff = 0;
private double pdiff = 0d;
int[] array = new int[numSides *numSides];
public Form1()
{
InitializeComponent();
}
private void Form1Load(object sender, EventArgs e)
{
SetupDataForm1();
SetupDataForm2();
var bw = new BackgroundWorker();
bw.DoWork += BwDoWork;
bw.RunWorkerAsync(); //Start the worker
}
private void BwDoWork(object sender, DoWorkEventArgs e)
{
for (int rolls = 1; rolls < numRolls+1; rolls++)
{
// Roll two dice and increase that slot in the table
int y = Dice.Roll(numSides, rnd);
int x = Dice.Roll(numSides, rnd);
int k = Convert.ToInt32(dataGridView1.Rows[x].Cells[y].Value);
dataGridView1.Rows[x].Cells[y].Value = k + 1;
//Enter table into an array to work out max/min etc later
for (int i = 0; i < (numSides * numSides); i++)
{
int row = i / numSides;
int col = i % numSides;
array[i] = Convert.ToInt32(dataGridView1.Rows[row].Cells[col].Value);
}
max = array.Max();
min = array.Min();
diff = max - min;
if (max > 0) pdiff = (((double)diff / (max)) * 100);
dataGridView2.Rows[0].Cells[0].Value = rolls;
dataGridView2.Rows[1].Cells[0].Value = max;
dataGridView2.Rows[2].Cells[0].Value = min;
dataGridView2.Rows[3].Cells[0].Value = diff;
dataGridView2.Rows[4].Cells[0].Value = pdiff.ToString("0.000");
dataGridView2.Rows[5].Cells[0].Value = (array.Average()).ToString("0");
dataGridView2.Rows[6].Cells[0].Value = ((array.Average()/rolls)*100).ToString(("0.0000000"));
}
}
private void SetupDataForm1()
{
dataGridView1.Font = new Font("Microsoft Sans Serif", 6F);
dataGridView1.RowTemplate.Height = 11;
//Add Columns
for (int i = 0; i < numSides; i++)
{
dataGridView1.Columns.Add(i.ToString(), (i+1).ToString());
dataGridView1.Columns[i].Width = 35;
}
// Add Rows
for (int i = 0; i < numSides; i++)
{
dataGridView1.Rows.Add();
if (i % 2 != 0)
{
dataGridView1.Rows[i].DefaultCellStyle.BackColor = Color.LightGray;
}
dataGridView1.Rows[i].HeaderCell.Value = ((i+1)*10).ToString();
}
}
private void SetupDataForm2()
{
dataGridView2.Font = new Font("Microsoft Sans Serif", 8F);
dataGridView2.RowTemplate.Height = 16;
//Add Columns
for (int i = 0; i < 1; i++)
{
dataGridView2.Columns.Add(i.ToString(), "");
dataGridView2.Columns[i].Width = 65;
}
// Add Rows
for (int i = 0; i < numSides; i++)
{
dataGridView2.Rows.Add();
if (i % 2 != 0)
{
dataGridView2.Rows[i].DefaultCellStyle.BackColor = Color.LightGray;
}
}
dataGridView2.Rows[0].HeaderCell.Value = "Rolls";
dataGridView2.Rows[1].HeaderCell.Value = "Max";
dataGridView2.Rows[2].HeaderCell.Value = "Min";
dataGridView2.Rows[3].HeaderCell.Value = "Diff";
dataGridView2.Rows[4].HeaderCell.Value = "%";
dataGridView2.Rows[5].HeaderCell.Value = "Avg";
dataGridView2.Rows[6].HeaderCell.Value = "Av%";
}
public class Dice
{
public static int Roll(int numberOfSides, Random rnd)
{
return rnd.Next(0, numberOfSides);
}
}
}
}
If there is no window, you perform the calculations in the form's constructor. To make the form visible before starting the calculation, put the code in the form's Load event. Therefore double click the event in the form's properties window and a method will be created. Put your code into this method.
If you want to use a background worker, the procedure is similar. However, you need to create the Backgroundworker. E.g. in code:
private void Form1_Load(object sender, EventArgs e)
{
var bw = new BackgroundWorker();
bw.DoWork +=
If you start typing that, Visual Studio suggests to create a method for the event. Press Tab twice to generate it and you'll basically get the following code:
private void Form1_Load(object sender, EventArgs e)
{
var bw = new BackgroundWorker();
bw.DoWork += bw_DoWork;
bw.RunWorkerAsync(); //Start the worker
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
throw new NotImplementedException(); //remove this
}
Put your calculation code in the bw_DoWork method an it will be executed in the background without affecting the user interface.