Microcontroller 8051 with matrix keyboard and LED display - keyboard

I have such a program, it works. I get the number from pressed button on the LED display. But I need to change this program so it shows the last 2 pressed numbers on the display, when I press * or #.
For example, I press '1 2 3 4 5 #'. On the display I see only two last numbers '4 5'. How can I do this?
#include <REGX52.h>
#define SEG P1
#define keypad P2
sbit r1 = P2^0;
sbit r2 = P2^1;
sbit r3 = P2^2;
sbit r4 = P2^3;
sbit c1 = P2^4;
sbit c2 = P2^5;
sbit c3 = P2^6;
sbit c4 = P3^7;
void scan(void);
unsigned int Display[12] = {0x0, 0x1, 0x2, 0x3,0x4,0x5,0x6,0x7,0x8,0x9};
void main(void)
{
while(1)
{
scan();
}
}
void scan(void){
r1=0;
r2=r3=r4=1;
if(c1==0)
{
while(c1==0){
P1=Display[1];
}
}
if(c2==0)
{
while(c2==0){
P1=Display[2];
}
}
if(c3==0)
{
while(c3==0){
P1=Display[3];
}
}
r2=0;
r1=r3=r4=1;
if(c1==0)
{
while(c1==0){
P1=Display[4];
}
}
if(c2==0)
{
while(c2==0){
P1=Display[5];
}
}
if(c3==0)
{
while(c3==0){
P1=Display[6];
}
}
r3=0;
r1=r2=r4=1;
if(c1==0)
{
while(c1==0){
P1=Display[7];
}
}
if(c2==0)
{
while(c2==0){
P1=Display[8];
}
}
if(c3==0)
{
while(c3==0){
P1=Display[9];
}
}
r4=0;
r1=r2=r3=1;
if(c2==0)
{
while(c2==0){
P1=Display[0];
}
}

unsigned int last_two_buttons[2] = {0x0, 0x0}; /* array of 2 elements to remember the last two buttons pressed. */
unsigned int update_display = 0; //flag to indicate if LED display needs to be updated.
Now, Instead of assigning P1 = Display[x] for each of the button pressed, you simply remember/store that button pressed in this array as follows:
last_two_buttons[0] = last_two_buttons[1];
last_two_buttons[1] = Display[x]; //x here indicates the button pressed, the same way as you have been using in your code.
Now, enhance the scan() to detect the * and the # buttons.
r4=0;
r1=r2=r3=1;
if(c1==0)
{
while(c1==0){
update_display = 1; // * button pressed
}
if(c3==0)
{
while(c3==0){
update_display = 1; // # button pressed
}
if(update_display)
{
P1 = last_two_buttons[0] <<4 + last_two_buttons[1];
update_display = 0; //reset the variables for next scan.
last_two_buttons[0] = 0;
last_two_buttons[1] = 0;
}
The assumption here is that, if the user presses only one button, say 5# then, we will be displaying 0 and 5 as the last two pressed buttons.
Hope this helps.

Related

How to make sound play only once on mouse over in Processing?

I'm trying to make a sound play when the mouse moves over a button in Processing. Currently, it is playing over and over again because my button class is in the draw() function. I understand why this is happening, but I can't think of a way to only play the sound once while still being tied to my overRect() function.
main:
import processing.sound.*;
PlayButton playButton;
SoundFile mouseOverSound;
SoundFile clickSound;
color white = color(255);
color gray = color(241, 241, 241);
PFont verdanabold;
void setup()
{
size(720, 1280);
textAlign(CENTER);
rectMode(CENTER);
verdanabold = createFont("Verdana Bold", 60, true);
playButton = new PlayButton();
mouseOverSound = new SoundFile(this, "mouseover.wav");
clickSound = new SoundFile(this, "click.mp3");
}
void draw()
{
background(gray);
playButton.display(); // draw play button
}
playButton class:
class PlayButton // play button
{
float rectX = width/2; // button x position
float rectY = height-height/4; // button y position
int rectWidth = 275; // button width
int rectHeight = 75; // button height
boolean rectOver = false; // boolean determining if mouse is over button
void display() // draws play button and controls its function
{
update(mouseX, mouseY);
if(rectOver) // controls button color when mouse over
{
fill(white);
mouseOverSound.play(); // play mouse over sound
}
else
{
fill(gray);
}
strokeWeight(5); // button
stroke(black);
rect(rectX, rectY, rectWidth, rectHeight);
textFont(verdanabold, 48); // button text
fill(black);
text("PLAY", rectX, rectY+15);
if(mousePressed && rectOver) // if mouse over and clicked, change to state 1
{
state = 1;
clickSound.play(); // play click sound
}
}
void update(float x, float y) // determines if mouse is over button using overRect(), changes boolean rectOver accordingly
{
if(overRect(rectX, rectY, rectWidth, rectHeight))
{
rectOver = true;
}
else
{
rectOver = false;
}
}
boolean overRect(float rectX, float rectY, int rectWidth, int rectHeight) // compares mouse pos to button pos and returns true if =
{
if(mouseX >= rectX-rectWidth/2 && mouseX <= rectX+rectWidth/2 && mouseY >= rectY-rectHeight/2 && mouseY <= rectY+rectHeight/2)
{
return true;
}
else
{
return false;
}
}
}
Figured it out.
Initialized int i = 0. While mouse is over the button, plays sound while i < 1, then increments i by 1 inside the while loop so it stops playing. When mouse is not over the button, i is set back to 0.
Edited playButton class:
class HowToButton // how to button
{
float rectX = width/2; // button x position
float rectY = height-height/8; // button y position
int rectWidth = 275; // button width
int rectHeight = 75; // button height
boolean rectOver = false; // boolean determining if mouse is over button
int i = 0;
void display() // draws how to button and controls its function
{
update(mouseX, mouseY);
if (rectOver) // controls button color when mouse over
{
fill(white);
while(i < 1) // play sound while i < 1
{
mouseOverSound.play(); // play mouse over sound
i++; // increment i so sound only plays once
}
}
else
{
fill(gray);
i = 0; // set i back to 0 when mouse leaves bounds of button
}
strokeWeight(5); // button
stroke(black);
rect(rectX, rectY, rectWidth, rectHeight);
textFont(verdanabold, 48); // button text
fill(black);
text("HOW TO", rectX, rectY+15);
if(mousePressed && rectOver) // if mouse over and clicked, change to state 2
{
state = 2;
clickSound.play(); // play click sound
}
}
void update(float x, float y) // determines if mouse is over button using overRect(), changes boolean rectOver accordingly
{
if(overRect(rectX, rectY, rectWidth, rectHeight))
{
rectOver = true;
}
else
{
rectOver = false;
}
}
boolean overRect(float rectX, float rectY, int rectWidth, int rectHeight) // compares mouse pos to button pos and returns true if =
{
if(mouseX >= rectX-rectWidth/2 && mouseX <= rectX+rectWidth/2 && mouseY >= rectY-rectHeight/2 && mouseY <= rectY+rectHeight/2)
{
return true;
}
else
{
return false;
}
}
}
You could use a boolean variable that indicates whether the sound is already playing. Something like this:
if(mousePressed && rectOver && !alreadyPlaying)
{
alreadyPlaying = true;
state = 1;
clickSound.play(); // play click sound
}
In fact, you might be able to use the state variable:
if(mousePressed && rectOver && state != 1)
{
state = 1;
clickSound.play(); // play click sound
}
You could also look into the sound library you're using, it might have a function that tells you whether the sound is already playing, which you could use in the same way.

How to draw a string to the screen character by character

I have the below code that creates a delay in-between drawing characters from a string, this works using println() however does not work when using the text() function. The code is supposed to wait an allotted time then print the next character, I'm really not sure what I'm doing wrong.
int startTimer;
int waitTime = 500;
boolean funcRun = true;
void setup(){
size(500, 500);
startTimer = millis();
}
void draw(){
while(funcRun){
textAnim("hello");
}
}
void textAnim(String textInput){
int counter = 0;
int x = 10;
while(counter < textInput.length()){
if(millis() - startTimer>waitTime){
text(textInput.charAt(counter), x , 100);
startTimer = millis();
++counter;
x = x + 10;
}
funcRun = false;
}
}
The displayed screen is updated at the end of the draw() function. So your while loop is fully executed and the completed text is shown. You'll have to modify the code such that it will constantly refresh/redraw the screen, and updates the displayed text based on the time loop.
For example like this:
int currentTime;
int waitTime = 500;
int characters_to_display = 0;
boolean stringComplete = false;
String textInput = "Hello";
void setup() {
size(500, 500);
currentTime = millis();
}
void draw() {
// Update text to be shown. increaseCharIndex() is called while the text is not yet fully displayed
if (stringComplete == false) {
increaseCharIndex();
}
//Draw screen:
// draw background to clear screen
background(0);
// display (a substring of) the text
text(textInput.substring(0, characters_to_display), 10, 100);
}
void increaseCharIndex() {
// if the waitperiod has passed, increase the number of characters to be displayed
if (millis() - currentTime>waitTime) {
currentTime = millis();
characters_to_display++;
}
// if the full text will be shown, end the call to increaseCharIndex()
if (characters_to_display >= textInput.length())
{
stringComplete = true;
}
}

Switch Sound Button in Unity Javascript code

I am trying to figure out how to use "sound off" and "sound on" images to control game sound. The code below displays a sound button but when you click on it, it mutes the sounds but adds a shaded circle over the button.
I would like some guide or how to make it switch from a sound on to a sound off image button as I am new to Unity.
Image File Names: SoundButton.psd and WhiteCircle.psd
var whiteCircle : GameObject;
var numberOfTouch : int = 0;
private var a : float = 1;
function Start() {
if (PlayerPrefs.GetInt("SoundBoolean") == 0) {
//check whether the sound is included, if turned on, then play sound.
numberOfTouch = 0;
whiteCircle.GetComponent(SpriteRenderer).enabled = false;
}
if (PlayerPrefs.GetInt("SoundBoolean") == 1) {
//check whether the sound is included, if turned off, then turn off the sound.
numberOfTouch = 1;
whiteCircle.GetComponent(SpriteRenderer).enabled = true;
}
}
function OnMouseDown () {
if (a <= 0) {
if (numberOfTouch == 0) {
//completely turn off the music.
a = 1;
numberOfTouch = 1;
gameObject.GetComponent.<AudioSource>().Play();
whiteCircle.GetComponent(SpriteRenderer).enabled = true;
PlayerPrefs.SetInt("SoundBoolean", 1);
PlayerPrefs.Save();
}
}
if (a <= 0) {
if (numberOfTouch == 1) {
//a fully turn on the music.
a = 1;
numberOfTouch = 0;
whiteCircle.GetComponent(SpriteRenderer).enabled = false;
PlayerPrefs.SetInt("SoundBoolean", 0);
PlayerPrefs.Save();
}
}
}
function Update() {
if (a >= 0) {
a -= 0.1;
}
}
As I understood correctly, you're looking for something to change the sprite on an object you have. I'm not testing my code or anything, but perhaps it can help you solve your problem.
var sprite1 : Sprite; // Drag your first sprite here
var sprite2 : Sprite; // Drag your second sprite here
var spriteRenderer : SpriteRenderer = whiteCircle.GetComponent(SpriteRenderer);
var whiteCircle : GameObject;
var numberOfTouch : int = 0;
private var a : float = 1;
function Start() {
if (PlayerPrefs.GetInt("SoundBoolean") == 0) {
//check whether the sound is included, if turned on, then play sound.
numberOfTouch = 0;
spriteRenderer.sprite = sprite2;
}
if (PlayerPrefs.GetInt("SoundBoolean") == 1) {
//check whether the sound is included, if turned off, then turn off the sound.
numberOfTouch = 1;
spriteRenderer.sprite = sprite1;
}
}
function OnMouseDown () {
if (a <= 0) {
if (numberOfTouch == 0) {
//completely turn off the music.
a = 1;
numberOfTouch = 1;
gameObject.GetComponent.<AudioSource>().Play();
spriteRenderer.sprite = sprite1;
PlayerPrefs.SetInt("SoundBoolean", 1);
PlayerPrefs.Save();
}
}
if (a <= 0) {
if (numberOfTouch == 1) {
//a fully turn on the music.
a = 1;
numberOfTouch = 0;
spriteRenderer.sprite = sprite2;
PlayerPrefs.SetInt("SoundBoolean", 0);
PlayerPrefs.Save();
}
}
}
function Update() {
if (a >= 0) {
a -= 0.1;
}
}
Basically, add two sprite points to where you can drag your image files, then replace the sprite on a certain spriterenderer (instead of turning it on and off).

Ardunio, decoding a string at postion N

I'm having this little problem with some easy code, basically what I'm doing is sending information via the serial port via a program I wrote in Java. The information is getting their for basic statements (IE, can turn on lights and stuff) but I'm having errors getting it to decode strings with number values send to it.
So for example, I'm sending strings that look like this
BS//:+000/+000/+000
and the decoding method I'm using looks like this.
After adding the string via this:
if (inputString.startsWith("BS//:")) //**fixed
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
Sends it too...
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt();
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();
baseStepperTime = baseStepper.substring(15,18).toInt();
}
Which should decode and run
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
Problem seems to be that it doesn't decode... ideas I'm sort of lost at this stage. :/
(total past of the code, I know the information is getting there, just not compiling like it should.)
#include <Stepper.h>
//#include <HardwareSerial.h>
// int intensity = 0; // led intensity this is needed just as example for this sketch
String inputString = ""; // a string to hold incoming data (this is general code you can reuse)
boolean stringComplete = false; // whether the string is complete (this is general code you can reuse)
int stepsPerRevolution = 64; //at 5.625 degrees a step
// initialize the stepper library on pins 8 through 11:
Stepper baseStepper(stepsPerRevolution, 2,3,4,5); // protocols start with //BS:
Stepper shoulderStepper(stepsPerRevolution, 6,7,8,9); // protocols start with //SS:
Stepper armStepper(stepsPerRevolution, 10,11,12,13); // protocols start with //AS:
//--------baseStepper--------//
int baseStepperRotCount = 0; //how many rotations in the for loop is needed
int baseStepperRotStepSize = 0; // how large should the steps be...
int baseStepperTime = 0; //delay time needed between each step (delay); so the stepper can do it's work.
//--------shoulderStepper--------//
int shoulderStepperRotCount =0;
void setup() {
// initialize serial: (this is general code you can reuse)
Serial.begin(115200);
}
void loop() {
// when a newline arrives:
if (stringComplete) {
//these are test if statements, they serve no purpose after the intial boot, but must be included to test the connectivity;
if (inputString.startsWith("alpha"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
inputString = "";
stringComplete = false;
}
else if (inputString.startsWith("beta"))
{
boolean msgRecognized = true;
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
inputString = "";
stringComplete = false;
}
//---------------------///
//these statements set the engines and prepare for running of the program.
if (inputString.startsWith("//BS:")) // "BS//:+000/+000/+000"
{
inputInfoToBaseStepper(inputString);
baseStepperRunAction(baseStepperRotCount, baseStepperRotStepSize, baseStepperTime);
}
else if (inputString.startsWith("//SS:"))
{
//inputInfoToShoulderStepper();
//outputConfirmed();
}
else if (inputString.startsWith("//AS:"))
{
//inputInfoToArmStepper();
// outputConfirmed();
}
if(inputString.startsWith("alp://")) { // OK is a message I know (this is general code you can reuse)
boolean msgRecognized = true;
if(inputString.substring(6,10) == "kprs") { // KeyPressed }
msgRecognized = false; // this sketch doesn't know other messages in this case command is ko (not ok)
// Prepare reply message if caller supply a message id (this is general code you can reuse)
int idPosition = inputString.indexOf("?id=");
if(idPosition != -1) {
String id = inputString.substring(idPosition + 4);
// print the reply
Serial.print("alp://rply/");
if(msgRecognized) { // this sketch doesn't know other messages in this case command is ko (not ok)
Serial.print("ok?id=");
} else {
Serial.print("ko?id=");
}
Serial.print(id);
Serial.write(255); // End of Message
Serial.flush();
}
}
// clear the string:
inputString = "";
stringComplete = false;
}
}
}
/*
Send listen messages
int index = 0;
for (index = 0; index < digitalPinListeningNum; index++) {
if(digitalPinListening[index] == true) {
int value = digitalRead(index);
if(value != digitalPinListenedValue[index]) {
digitalPinListenedValue[index] = value;
Serial.print("alp://dred/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255);
Serial.flush();
}
}
}
for (index = 0; index < analogPinListeningNum; index++) {
if(analogPinListening[index] == true) {
int value = analogRead(index);
if(value != analogPinListenedValue[index]) {
analogPinListenedValue[index] = value;
Serial.print("alp://ared/");
Serial.print(index);
Serial.print("/");
Serial.print(value);
Serial.write(255); // End of Message
Serial.flush();
}
}
}
} */
//this method decodes and stores inputs
void inputInfoToBaseStepper(String baseStepper)
{
baseStepperRotCount = baseStepper.substring(6,9).toInt(); // B S / / : + 0 0 0 / + 0 0 0 / + 0 0 0
baseStepperRotStepSize = baseStepper.substring(10,13).toInt();// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
baseStepperTime = baseStepper.substring(15,18).toInt();
}
//this method runs the base stepper off the decoded actions.
void baseStepperRunAction (int rotations, int StepSize, int delayTime)
{
for (int rotations; rotations >=0; rotations--)
{
baseStepper.step(StepSize);
delay(delayTime);
}
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
This is general code you can reuse.
*/
void serialEvent() {
while (Serial.available() && !stringComplete) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') {
stringComplete = true;
}
}
}

Is there a way to use normal ASCII characters (like a comma) as wxWidgets menu accelerators?

I want a few menu entries that show accelerators that are normal keys, like the space-bar or comma key, but I don't want wxWidgets to make those accelerators itself (because then they can't be used anywhere in the program, including in things like edit boxes).
Unfortunately, wxWidgets insists on always making anything it recognizes in that column into an accelerator under its control, and simply erases anything it doesn't recognize.
I'm looking for some way to either put arbitrary text into the accelerator column (which I don't think exists, I've looked at the source code), or get 'hold of the accelerator table used for the menus so I can modify it myself (haven't found it yet). Can anyone point me in the right direction?
You can try wxKeyBinder. It allows you to bind hotkeys to commands (usually menu entries), save/load/add/remove/modify ... them easily
I couldn't find a way to access the menu's accelerator keys directly, but modifying the accelerator menu text works just as well. Here's the code I came up with:
In a header file:
class accel_t {
public:
// If idcount == -1, idlist must be null or terminated with a -1 entry.
accel_t(): mMenu(0) { }
accel_t(wxMenuBar *m, int *idlist = 0, int idcount = -1);
void reset(wxMenuBar *m, int *idlist = 0, int idcount = -1);
void restore() const;
void remove() const;
private: //
struct accelitem_t {
accelitem_t(int _id, wxAcceleratorEntry _key): id(_id), hotkey(_key) { }
int id;
wxAcceleratorEntry hotkey;
};
typedef std::vector<accelitem_t> data_t;
void noteProblemMenuItems(wxMenu *m);
static bool isProblemAccelerator(wxAcceleratorEntry *a);
wxMenuBar *mMenu;
data_t mData;
};
In a cpp file:
accel_t::accel_t(wxMenuBar *m, int *idlist, int idcount) {
reset(m, idlist, idcount);
}
void accel_t::reset(wxMenuBar *m, int *idlist, int idcount) {
mMenu = m;
mData.clear();
if (idlist == 0) {
for (int i = 0, ie = m->GetMenuCount(); i != ie; ++i)
noteProblemMenuItems(m->GetMenu(i));
} else {
if (idcount < 0) {
int *i = idlist;
while (*i != -1) ++i;
idcount = (i - idlist);
}
for (int *i = idlist, *ie = i + idcount; i != ie; ++i) {
wxMenuItem *item = mMenu->FindItem(*i);
if (item) {
wxAcceleratorEntry *a = item->GetAccel();
if (a != 0) mData.push_back(accelitem_t(*i, *a));
}
}
}
}
bool accel_t::isProblemAccelerator(wxAcceleratorEntry *a) {
if (a == 0) return false;
int flags = a->GetFlags(), keycode = a->GetKeyCode();
// Normal ASCII characters, when used with no modifier or Shift-only, would
// interfere with editing.
if ((flags == wxACCEL_NORMAL || flags == wxACCEL_SHIFT) &&
(keycode >= 32 && keycode < 127)) return true;
// Certain other values, when used as normal accelerators, could cause
// problems too.
if (flags == wxACCEL_NORMAL) {
if (keycode == WXK_RETURN ||
keycode == WXK_DELETE ||
keycode == WXK_BACK) return true;
}
return false;
}
void accel_t::noteProblemMenuItems(wxMenu *m) {
// Problem menu items have hotkeys that are ASCII characters with normal or
// shift-only modifiers.
for (size_t i = 0, ie = m->GetMenuItemCount(); i != ie; ++i) {
wxMenuItem *item = m->FindItemByPosition(i);
if (item->IsSubMenu())
noteProblemMenuItems(item->GetSubMenu());
else {
wxAcceleratorEntry *a = item->GetAccel();
if (isProblemAccelerator(a))
mData.push_back(accelitem_t(item->GetId(), *a));
}
}
}
void accel_t::restore() const {
if (mMenu == 0) return;
for (data_t::const_iterator i = mData.begin(), ie = mData.end(); i != ie;
++i)
{
wxMenuItem *item = mMenu->FindItem(i->id);
if (item) {
wxString text = item->GetItemLabel().BeforeFirst(wxT('\t'));
wxString hotkey = i->hotkey.ToString();
if (hotkey.empty()) {
// The wxWidgets authors apparently don't expect ASCII
// characters to be used for accelerators, because
// wxAcceleratorEntry::ToString just returns an empty string for
// them. This code deals with that.
int flags = i->hotkey.GetFlags(), key = i->hotkey.GetKeyCode();
if (flags == wxACCEL_SHIFT) hotkey = wx("Shift-") + wxChar(key);
else hotkey = wxChar(key);
}
item->SetItemLabel(text + '\t' + hotkey);
}
}
}
void accel_t::remove() const {
if (mMenu == 0) return;
for (data_t::const_iterator i = mData.begin(), ie = mData.end(); i != ie;
++i)
{
wxMenuItem *item = mMenu->FindItem(i->id);
if (item) {
wxString text = item->GetItemLabel().BeforeFirst(wxT('\t'));
item->SetItemLabel(text);
}
}
}
The easiest way to use it is to create your menu-bar as normal, with all accelerator keys (including the problematic ones) in place, then create an accel_t item from it something like this:
// mProblemAccelerators is an accel_t item in the private part of my frame class.
// This code is in the frame class's constructor.
wxMenuBar *menubar = _createMenuBar();
SetMenuBar(menubar);
mProblemAccelerators.reset(menubar);
It will identify and record the accelerator keys that pose problems. Finally, call the remove and restore functions as needed, to remove or restore the problematic accelerator keys. I'm calling them via messages passed to the frame whenever I open a window that needs to do standard editing.

Resources