Counter function
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
Ok, that's kind of what I was thinking. I really need to test, I have both a buzzer and a piezo, I just don't know which will be loud enough for my needs.
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
The best way to handle such issues is to say, "I don't know, so I'm going to build a circuit and find out". An ounce of experimental data is worth a ton of speculation.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
The buzzer is definitely loud enough, I hooked it up to 5V yesterday.
https://www.adafruit.com/product/1536
I tried hooking it up for a test on the board, using pin 11, so it would hook to 11 and ground. The buzzer didn't seem to work that way?
My code compiled fine, would it be because that is a pwm pin?
https://www.adafruit.com/product/1536
I tried hooking it up for a test on the board, using pin 11, so it would hook to 11 and ground. The buzzer didn't seem to work that way?
My code compiled fine, would it be because that is a pwm pin?
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
It wouldn't be a PWM problem unless you used 'analogWrite()'. That's what generates PWM signals on those pins.
You probably ran into the pin's current limit. An Arduino's pin can deliver 40mA of current at most, and that's probably a lot less than you were getting when you hooked the buzzer up to a 5v supply.
You can solve that by using the Arduino's pin to control a transistor, and letting the transistor control the buzzer. An N-mosfet would be easiest to hook up because they're controlled by voltage and use no DC current: https://www.adafruit.com/products/355 Just connect the Source pin to GND, the Drain pin to the buzzer, and the Gate pin to the Arduino.
You probably ran into the pin's current limit. An Arduino's pin can deliver 40mA of current at most, and that's probably a lot less than you were getting when you hooked the buzzer up to a 5v supply.
You can solve that by using the Arduino's pin to control a transistor, and letting the transistor control the buzzer. An N-mosfet would be easiest to hook up because they're controlled by voltage and use no DC current: https://www.adafruit.com/products/355 Just connect the Source pin to GND, the Drain pin to the buzzer, and the Gate pin to the Arduino.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
That makes sense, I used the command digitalWrite, and never even though about it. So how much current does a small speaker like that require to operate? There isn't any info in the technical section. I have the transistors we discussed earlier in the thread, I'm assuming those would work as well? I was really hoping that the arduino would be able to supply enough current to operate it.
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
Without seeing a datasheet for the buzzer, it's hard to say. Most audio devices are inefficient transducers though.. only about 5% of the electrical power you put through them gets converted to actual sound waves.
Again though, direct measurement trumps all other forms of reasoning. Reconnect the buzzer to your 5v supply but run the connection through a multimeter set to measure current. To save yourself a headache, start at the highest current setting and work your way down. Most multimeters have two current ranges.. 1-10A, and less-than-1A. The components for the lower-current side are protected by a fuse, but it's still a nuisance to blow that fuse if you don't have a spare handy.
You can control the buzzer with BJTs, but you'll need a resistor between the Arduino's pin and the base of the transistor, and the size of that resistor depends on the amount of current the buzzer wants.
Again though, direct measurement trumps all other forms of reasoning. Reconnect the buzzer to your 5v supply but run the connection through a multimeter set to measure current. To save yourself a headache, start at the highest current setting and work your way down. Most multimeters have two current ranges.. 1-10A, and less-than-1A. The components for the lower-current side are protected by a fuse, but it's still a nuisance to blow that fuse if you don't have a spare handy.
You can control the buzzer with BJTs, but you'll need a resistor between the Arduino's pin and the base of the transistor, and the size of that resistor depends on the amount of current the buzzer wants.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
Question, I also got some of the I/O expander chips that use the I2C pins. How do I address those in my code?
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
The easiest way to do that is to create one MCP23008/MCP23017 object for each chip.
Every chip will need its own address, which you can set by connecting the address pins HIGH or LOW. The base address is 0x20, and the address pins allow you to set the last three bits of that (0x20 through 0x27).
To set the address each object uses, just call its 'begin()' method with the address for that specific chip:
You only need the part defined by the address pins because the library combines that with the base device address.
Every chip will need its own address, which you can set by connecting the address pins HIGH or LOW. The base address is 0x20, and the address pins allow you to set the last three bits of that (0x20 through 0x27).
To set the address each object uses, just call its 'begin()' method with the address for that specific chip:
Code: Select all
Adafruit_MCP23017 mcp0;
Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
void setup() {
mcp0.begin( 0 );
mcp1.begin( 1 );
mcp2.begin( 2 );
}
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
Code: Select all
Adafruit_MCP23017 mcp0; //Establishes IO chip #1
Adafruit_MCP23017 mcp1; //Establishes IO chip #2
Adafruit_MCP23017 mcp2; //Establishes IO chip #3
void setup() {
mcp0.begin( 0 ); //Establishes IO chip #1, Pin 0
mcp1.begin( 1 ); //Establishes IO chip #2, Pin 1
mcp2.begin( 2 ); //Establishes IO chip #3, Pin 2
}
So basicallyis this correct then? Iif so, how do I define input/output? I'm still fuzzy on this one, could you dumb it down a little more? Basically when all is said and done, I'll have a few of these expansion chips hooked up to both inputs and outputs, and a display, this one specifically.
https://www.adafruit.com/product/181
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
Whenever you need to deal with a new code library, the first place to looks for clues is the header file.
In C and C++, there's a rule that says you have to tell the compiler what's coming. It's called 'declaring' functions, and at a technical level it gives the compiler enough information to allocate space in memory for any function call. To do that, you tell the compiler each function's 'signature': its name, what it takes as input, and what it returns. A convenient side-effect of function declarations is that you get a short list of "what does this library do?" information that's usually stored in a single place (the header file).
Our programmers have the additional good habit of giving functions names that tell you what they do, so a quick skim through the declarations in the header will usually give you enough information to start programming.
For the MCP230** port expanders, the declarations look like this:
and you can pretty much ignore the last two.
We chose names that match the ones used for IO on an Arduino, so the code will look similar to what you already know:
The 'pullUp()' function tells the chip to use a built-in pull-up resistor on the selected pin. That way you don't need an external resistor if you want to use one of the pins to read a switch.
Our programmers are also good about writing example sketches that show how to use the functions in a library with the actual hardware. On our side it's a quick way to tell whether hardware is working, but on your side it's starter code you can copy and tinker with.
WRT the LCD, your life will probably be easier if you pick up one of these as well: https://www.adafruit.com/products/292
The Arduino library has a built-in library to handle LCDs, but it only knows how to use the Arduino's own pins. The LCD controller linked above uses the MCP23008 to run an LCD through the same kind of port expander we're already talking about, so hooking up the LCD won't cost you any extra pins.
In C and C++, there's a rule that says you have to tell the compiler what's coming. It's called 'declaring' functions, and at a technical level it gives the compiler enough information to allocate space in memory for any function call. To do that, you tell the compiler each function's 'signature': its name, what it takes as input, and what it returns. A convenient side-effect of function declarations is that you get a short list of "what does this library do?" information that's usually stored in a single place (the header file).
Our programmers have the additional good habit of giving functions names that tell you what they do, so a quick skim through the declarations in the header will usually give you enough information to start programming.
For the MCP230** port expanders, the declarations look like this:
Code: Select all
void begin(void);
void pinMode(uint8_t p, uint8_t d);
void digitalWrite(uint8_t p, uint8_t d);
void pullUp(uint8_t p, uint8_t d);
uint8_t digitalRead(uint8_t p);
uint8_t readGPIO(void);
void writeGPIO(uint8_t);
We chose names that match the ones used for IO on an Arduino, so the code will look similar to what you already know:
Code: Select all
mcp1.pinMode( 3, INPUT );
uint8_t pin1_3 = mcp1.digitalRead( 3 );
mcp1.pinMode( 4, OUTPUT );
mcp1.digitalWrite( 4, HIGH );
delay( 10 );
mcp1.digitalWrite( 4, LOW );
// etc
Our programmers are also good about writing example sketches that show how to use the functions in a library with the actual hardware. On our side it's a quick way to tell whether hardware is working, but on your side it's starter code you can copy and tinker with.
WRT the LCD, your life will probably be easier if you pick up one of these as well: https://www.adafruit.com/products/292
The Arduino library has a built-in library to handle LCDs, but it only knows how to use the Arduino's own pins. The LCD controller linked above uses the MCP23008 to run an LCD through the same kind of port expander we're already talking about, so hooking up the LCD won't cost you any extra pins.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
I'm catching bits and pieces of this, but let's go through this applied to my project.
I have two lasers, and two photo-resistors, each hooked to a different expansion chip (732).
What do I have to declare in the header?
Can they be used as integers, and how do I notate?
What do I have to declare in the "void setup()"?
How do I reference them in the "void loop()"?
I wrote this, and it may be terrible, I'm just trying to work through it in my head. If we could use this as an example, it'd help me run through it.
I have two lasers, and two photo-resistors, each hooked to a different expansion chip (732).
What do I have to declare in the header?
Can they be used as integers, and how do I notate?
What do I have to declare in the "void setup()"?
How do I reference them in the "void loop()"?
I wrote this, and it may be terrible, I'm just trying to work through it in my head. If we could use this as an example, it'd help me run through it.
Code: Select all
//*****************************************************************************************
//*** My attempted understanding of how to address and incorporate ***
//*** expansion chips in a program ***
//*****************************************************************************************
Adafruit_MCP23017 mcp0; //Establishes IO chip #0
Adafruit_MCP23017 mcp1; //Establishes IO chip #1
int pr1.1 = mcp0.0; //Establishes integer to represent Chip0,Pin0
int pr1.2 = mcp0.1; //Establishes integer to represent Chip0,Pin1
int laser1.1 = mcp1.0; //Establishes integer to represent Chip1,Pin0
int laser1.2 = mcp1.1; //Establishes integer to represent Chip1,Pin1
int buzzer = 3; //Establishes buzzer to represent Uno, Pin3
int sw1 = 4; //Establishes start switch as Uno, Pin4
void setup()
{
mcp0.config(0, input); //Establishes Chip0,Pin0 as input
mcp0.config(1, input); //Establishes Chip0,Pin1 as input
mcp1.config(0, output); //Establishes Chip1,Pin0 as output
mcp1.config(1, output); //Establishes Chip1,Pin1 as output
}
void loop()
{
if (digital read(sw1) == high) //If SW1 is on,
{
digital write(laser1.1, high); //turn on laser1.1
digital write(laser1.2, high); //turn on laser1.2
}
if (digital read(laser1.1, high); //if laser1.1 is on
&& digital read(laser1.2, high); //and if laser1.2 is on
&& digital read(pr1.1) == low //and photo resistor1.1 is off
|| digital read(pr1.2) == low //or photo resistor1.2 is off
{
digital write(buzzer, high); //then turn on buzzer
delay(100); //for 100 milliseconds
digital write(buzzer, low); //then turn off buzzer
}
}
Last edited by adafruit_support_mike on Tue May 20, 2014 11:48 pm, edited 1 time in total.
Reason: added CODE tags to preserve the formatting
Reason: added CODE tags to preserve the formatting
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
You're close on the setup.. the ideas are right, it's just a matter of getting the exact vocabulary:
The MCP23107 library uses a function called 'pinMode()' to set the input/output status of a chip's pins, just like regular Arduino code uses 'pinMode()' to set the IO status of the Arduino's pins.
This part won't work though:
I see what you're trying to do, but there's no good way to make the kind of shortcuts you're looking for. It would be better to rename the objects that control the chips like so:
so you can write the rest of the code like this:
You need to use capital letters for INPUT, OUTPUT, HIGH, and LOW because the compiler cares about capitalization. 'HIGH' and 'high' are two different things as far as the compiler is concerned.
I added a boolean value to keep track of the laser state because it's easier than calling the chip and asking for the information. There's also some conceptual funkiness associated with reading the value of a pin that's been set to OUTPUT.
Code: Select all
Adafruit_MCP23017 mcp0; //Establishes IO chip #0
Adafruit_MCP23017 mcp1; //Establishes IO chip #1
void setup()
{
mcp0.pinMode(0, INPUT); //Establishes Chip0,Pin0 as input
mcp0.pinMode(1, INPUT); //Establishes Chip0,Pin1 as input
mcp1.pinMode(0, OUTPUT); //Establishes Chip1,Pin0 as output
mcp1.pinMode(1, OUTPUT); //Establishes Chip1,Pin1 as output
}
This part won't work though:
Code: Select all
int pr1.1 = mcp0.0; //Establishes integer to represent Chip0,Pin0
int pr1.2 = mcp0.1; //Establishes integer to represent Chip0,Pin1
int laser1.1 = mcp1.0; //Establishes integer to represent Chip1,Pin0
int laser1.2 = mcp1.1; //Establishes integer to represent Chip1,Pin1
[...]
digital write(laser1.1, high); //turn on laser1.1
digital write(laser1.2, high); //turn on laser1.2
Code: Select all
Adafruit_MCP23017 pr1; //Establishes IO chip #0
Adafruit_MCP23017 laser1; //Establishes IO chip #1
Code: Select all
Adafruit_MCP23017 pr1; //Establishes IO chip #0
Adafruit_MCP23017 laser1; //Establishes IO chip #1
int buzzer = 3; //Establishes buzzer to represent Uno, Pin3
int sw1 = 4; //Establishes start switch as Uno, Pin4
void setup()
{
pr1.pinMode(0, INPUT); //Establishes Chip0,Pin0 as input
pr1.pinMode(1, INPUT); //Establishes Chip0,Pin1 as input
laser1.pinMode(0, OUTPUT); //Establishes Chip1,Pin0 as output
laser1.pinMode(1, OUTPUT); //Establishes Chip1,Pin1 as output
pinMode( buzzer, OUTPUT ); // Need to set these guys up too
pinMode( sw1, INPUT );
}
void loop()
{
boolean laser1_ON = false;
if (digitalRead(sw1) == HIGH) //If SW1 is on,
{
laser1.digitalWrite( 0, HIGH ); // turn on laser1.1
laser1.digitalWrite( 1, HIGH ); // turn on laser1.2
laser1_ON = true; // set the boolean so we know they're on
}
if (( laser1_ON ) // if the lasers are on
&& ( pr1.digitalRead( 0 ) == LOW ) // and photo resistor1.1 is off
|| ( pr1.digitalRead( 1 ) == LOW ) // or photo resistor1.2 is off
{
digitalWrite( buzzer, HIGH ); // then turn on buzzer
delay(100); // for 100 milliseconds
digitalWrite( buzzer, LOW ); // then turn off buzzer
}
}
I added a boolean value to keep track of the laser state because it's easier than calling the chip and asking for the information. There's also some conceptual funkiness associated with reading the value of a pin that's been set to OUTPUT.
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
So the boolean value is more or less just a status bit then right? Can that be set per pin on each chip? The reason I ask is that I'm wanting to say if the laser is on, but the photo resistor is off, I want the laser to turn off. This will be true for each laser / photo resistor pair.
I guess initially, if pins 1-8 on a chip are lasers, the boolean bit would be 11111111, right? I read somewhere that there are two batches per chip, right? So basically you could have two boolean bits per chip?
I guess initially, if pins 1-8 on a chip are lasers, the boolean bit would be 11111111, right? I read somewhere that there are two batches per chip, right? So basically you could have two boolean bits per chip?
- adafruit_support_mike
- Posts: 67485
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Counter function
A boolean is conceptually the same as a status bit, yes. The compiler may store the information in some other way, but yeah, it boils down to a yes/no value.
Since you want to store a lot of boolean values, your code will probably be easier to read and write if you use direct bit manipulation and a few wrapper functions.
The basic bit-manipulation operators are:
'&' - logical AND
'|' - logical OR
'~' - logical NOT
'^' - logical XOR
and it's often useful to shift bits to a specific location:
'<< n' - shift n bits left
'>> n' - shift n bits right
Bit operations make efficient code, but they're kind of hard to read. It's also easy to make mistakes when writing them, so it's usually best to create simple functions that wrap the operations in human-readable names:
Since you want to store a lot of boolean values, your code will probably be easier to read and write if you use direct bit manipulation and a few wrapper functions.
The basic bit-manipulation operators are:
'&' - logical AND
'|' - logical OR
'~' - logical NOT
'^' - logical XOR
and it's often useful to shift bits to a specific location:
'<< n' - shift n bits left
'>> n' - shift n bits right
Bit operations make efficient code, but they're kind of hard to read. It's also easy to make mistakes when writing them, so it's usually best to create simple functions that wrap the operations in human-readable names:
Code: Select all
Adafruit_MCP23017 mcp1;
uint8_t laser1_status = 0;
uint8_t photo1_status = 0;
#define NO_BEAM 0
#define HARDWARE_ERROR 1
#define BEAM_BROKEN 2
#define BEAM_UNBROKEN 3
void turn_on_laser1_item( int item );
void turn_off_laser1_item( int item );
void check_photo1_item( int item );
int status_of_set1_item( int item );
void loop() {
for ( int i=0 ; i < 8 ; i++ ) {
turn_on_laser1_item( i );
}
delay( 1000 );
for ( int i=0 ; i < 8 ; i++ ) {
check_photo1_item( i );
if ( status_of_set1_item( i ) == BEAM_BROKEN ) {
turn_off_laser1_item( i );
}
}
}
void turn_on_laser1_item( int item ) {
mcp1.digitalWrite( item, HIGH );
laser1_status = laser1_status | ( 1 << item );
/*
OR-ing with 1 will always set the bit in question to 1
OR-ing with 0 will always leave a bit unchanged
( 1 << item ) creates a mask that will always set bit
number 'item' to 1 and leave everything else unchanged
*/
}
void turn_off_laser1_item( int item ) {
mcp1.digitalWrite( item, LOW );
laser1_status = laser1_status & ~( 1 << item );
/*
AND-ing with 0 will always set the bit in question to 0
AND-ing with 1 will always leave a bit unchanged
~( 1 << item ) starts by creating the same mask we used
for the OR up above, then inverts all the bits so we have
a single 0 in a set of 1s.
AND-ing with that will always set bit number 'item' to 0
and leave everything else unchanged
*/
}
void check_photo1_item( int item ) {
int pinState = mcp1.digitalRead( item + 8 );
if (pinState == HIGH) {
photo1_status = photo1_status | ( 1 << item );
} else {
photo1_status = photo1_status & ~( 1 << item );
}
/*
The logical operations here are the same as before,
but we're using another byte of status bits
*/
}
int status_of_set1_item( int item ) {
int laser = ( laser1_status >> item ) & 1; // get the laser bit
int photo = ( photo1_status >> item ) & 1; // get the photo bit
return( ( laser * 2 ) + photo );
/*
Building a number out of status bits is a fast way to do logical
tests on them.
In this case, our result codes will be:
laser off, photo low : 0
laser off, photo high : 1 (something is wrong with the hardware)
laser on, photo low : 2 (beam broken)
laser on, photo high : 3 (beam not broken)
The macros I created at the start put human-readable names on those
results
*/
}
-
- Posts: 26
- Joined: Tue Mar 25, 2014 4:34 pm
Re: Counter function
I'm messing around with addressing on my breadboard, and I keep getting this error when I try to compile this code.
Also, is there an image of how exactly to wire up the I2C connections for these chips (732)?
Also, is there an image of how exactly to wire up the I2C connections for these chips (732)?
Please be positive and constructive with your questions and comments.