I have two shields which conveniently (ie no pin clash) share a port and I need to be able to manipulate just SOME pins on the port. But I cannot be sure if I am manipulating pins on or off, I just want to set them arbitrarily as the need arrises, ie, in one operation I may be turning some pins on and some off.
I do know:
PORTX |= B11110000 // turns on bits 4-7
PORTX &= B11000011 // turns off bits 2-5
PORTX ^= B00111111 // toggles bits 0-5
My challenge has been to turn on AND off only some pins, leaving others unchanged.
I have achieved the desired result, and in as far as I think I have done it in a safe way, I want to confirm it is in fact SAFE, and have I gone about it the right (best) way, or can I achieve this a much simpler way.
First, I am using PORTD, pins 4-7. I set those pins as outputs and then set them all as low to ensure my program starts with them (4x relays) all off.
void initRelays(){
RELAYDDR |= B11110000;
RELAYPORT &= ~RELAYDDR;
}
I believe tis will set pins 4-7 off without modifying the lower bits due to the bitwise AND with ZERO. I believe this will leave bit 0-3 as they were previously set.
Inverting this value and ANDing it with the existing port value, will ensure those pins are off and leaves the other bits unchanged. I'm sure this line is not required, I am having it here for safety sake :)
I have left the comments in the below code in order for you to try and understand what I am doing.
void relayPush(byte stack){
// stack has bit 1 to relay 1 (pin 4), thru bit 4 to relay 4 (pin 7)
// take stack and isolate the four bottom bits (the information we want to convert)
stack &= B00001111; // (1) I think this line is probably not required
// now shift to the position we need
stack <<= 4; // (2)
// OR the new stack with the PORT
// (this turns on any relays set in stack)
RELAYPORT |= stack; // (3)
// we need to NOT modify the bottom bits of the port
// mark those with a '1' so as to not turn them off
// bottom of stack mask = 0x0f
// XOR stack and mask
stack ^= 0x0f; // (4)
// AND new stack and port to turn off appropriate relays
RELAYPORT &= stack; // (5)
}
I know I have done it in two PORT operations, and I could make this one by using a temp variable, that's not of a major concern since it's only turning everything required to be on in the first instance and then turning everything off thats required in the second instance.
Have a missed a simpler way of doing this?
edit: I have had a look at what #Ignacio has said about changing the final operations and this is what I've come up with:
0011 0011 current port assignment
xxxx 1010 current stack assignment (we only want the lower nibble)
1010 0011 desired result
0011 0011 current port
xxxx 1010 current stack
0000 1111 step 1 - apply this mask to stack
0000 1010 resultant stack
1010 0000 step 2 - stack << 4
0011 0011 PORT
1010 0000 STACK
1010 0011 step 3 - resultant PORT (port OR stack)
0000 1111 (MASK for step 4)
1010 0000 stack at step 4
1010 1111 step 4 - resultant stack (mask XOR stack)
1010 0011 port from step 3
1010 1111 stack from step 4
1010 0011 port AND stack (desired result)
/// changing steps 4 and 5 to drop XOR, and applying complement
1010 0000 stack prior to step 4
0101 1111 ~stack
1010 0011 port from step 3
0000 0011 stack AND port (not the desired result)
summary:
XOR is needed to populate the bottom nibble to B00001111 and leaving top nibble unchanged. Since we know the bottom nibble is ZERO (from earlier shift), we could simply add 0x0F. XOR achieves the same thing.
For the final AND operation, we need to switch off top nibble ZEROs. Hence, no complement.
New idea from my comment to #Ignacio:
0011 0011 current port
xxxx 1010 current stack
1010 0000 shifted stack
0000 0011 temp = port AND 0x0F
1010 0011 stack OR temp (desired result)
Sorry for the long post, but I think that is a better solution, although it does use another variable.
Your and operation with RELAYPORT clears the upper 4 bits. You should not perform the earlier xor operation and instead should just and it with the complement.
RELAYPORT &= ~stack;
Some thoughts ... based on my experience with megaAVR's (esp. AT90USB1287)
When you split a port and operate some bits as input and some bits as output, I recommend to take extra care when writing the whole output port. There are good BIT instructions in the AVR. If you want to write a complete port, keep in mind that writing to bits configured as input does have an effect, namely to activate (PORTxy<-1) or deactivate (PORTxy<-0) internal pullup resistors - so depending on your hardware you have to choose what to use for the "unwanted" bits (with another dependency on MCUCR(PUD). In other words, the (to-be-ignored) input bits in a register you write out can't contain any random values but exactly the ones that support the configuration of the internal pullups. Insofar it's not usefull to read in a PINx before writing (parts) back to the port. (This was used on older processors with port hardware less elaborated than the AVR processors)
When writing out a PORTx insert a NOP before reading back PINx (due to the internal latch).
In initRelays() I'd use a constant, because it compiles faster (single instruction) rather than a function of RELAYDDR which involves reading back RELAYDDR into a register and writing the register to RELAYPORT.
Related
I understand that when subtracting binaries you should convert the second binary to it's 2's Complement. But in the following case:
01101+11110
The 11110 was converted to its 2's Complement. In other words the working equation is now:
01101+00010
Now I am pretty confused on when I should be converting. Any help would be greatly appreciated!
What I commented maybe not precise enough, though. I mistake CARRY for OVERFLOW.
-
So explain it little further
Your operation is:
01101 (binary) + 11110 (binary) = 01011 (binary)
-
if signed (CORRECT RESULT):
13 (decimal) + -2 (decimal) = 11 (decimal)
if unsigned (UNDESIRED RESULT):
13 (decimal) + 30 (decimal) = 11 (decimal)
-
There are two things in a binary arithmetic operation called separately OVERFLOW and CARRY.
For addition operation, The CARRY flag is set if the
addition of two numbers causes a carry out of the most significant
(leftmost) bits added.
example:
1111 + 0001 = 0000 (carry flag is turned on)
0111 + 0001 = 1000 (carry flag is turned off)
For subtraction operation, The CARRY flag is set if the
the subtraction of two numbers requires a borrow into the most significant (leftmost)
bits subtracted.
example:
0000 - 0001 = 1111 (carry flag is turned on)
1000 - 0001 = 0111 (carry flag is turned off)
For addition operation, the OVERFLOW flag is set if the
addition of two numbers with the same most significant bit (both 0 or
both 1) and the result produced a binary with a different most
significant bit.
example:
0100 + 0100 = 1000 (overflow flag is turned on)
0100 + 0001 = 0101 (overflow flag is turned off)
-
Note that:
In unsigned arithmetic, watch the carry flag to detect errors.
In signed arithmetic, the carry flag tells you nothing interesting.
-
In signed arithmetic, watch the overflow flag to detect errors.
In unsigned arithmetic, the overflow flag tells you nothing interesting.
-
check error in adding unsigned binaries in assembly language
ADD BX, AX
//check carry here
check error in subtracting unsigned binaries in assembly language
SUB BX, AX
//check carry here
check error in adding signed binaries in assembly language
ADD BX, AX
//check overflow here
check error in subtracting signed binaries in assembly language
SUB BX, AX
//check overflow here
See this for detail of the flag sets in ADD/SUB
carry/overflow & subtraction in x86
As you have understood correctly you want to do a twos complement. Logic will use addition to do subtraction by taking advantage of the beauty of twos complement.
One of the ways we are taught to "take the twos complement" is to invert (ones complement) and add one.
So if you want to do 4 - 7 (0b00100 - 0b00111)
That is the same as 0b00100 + 0b11000 + 1, can take advantage of the carry in of the lsbit:
1
00100
+ 11000
========
Do the grade school math in base 2.
000001
00100
+ 11000
========
11101
which is -3 if this is interpreted as a signed operation (same add/subtract logic for signed and unsigned, processor doesn't know, only the programmer does).
I assume instead of
01101+11110
you wanted to subtract those two numbers
01101-11110 13 - (-2) if interpreted as signed numbers
000011
01101
+ 00001
========
01111
13 + 2 = 15
the carry in and the carry out of the msbit are the same so there is no signed overflow the result is good. Note there isn't an unsigned overflow either.
So for subtraction you invert the carry in and the second operand from what you would for addition. Some processor architectures invert the carry out to indicate a borrow, some don't. You have check the architecture of the processor you are using to know if yours does. Unfortunately few do a good job at that level of documentation so sometimes you have to figure it out experimentally.
For addition you do not invert any of the operands into the adder. The operation (add vs sub) determines whether or not you invert on the way into the adder.
My hardware currently has four sets of sensors that I treat as four separate serial ports with receive functionality only enabled wired to the lower 4 bits of port 0. I have attempted numerous times to retrieve the correct serial port data (by aiming the lazer direct at the sensor) without success. I then researched that for more reliability, on a standard UART, each bit is sampled at 16x a second (I found this 3/4 down the page on https://www.allaboutcircuits.com/technical-articles/back-to-basics-the-universal-asynchronous-receiver-transmitter-uart/).
So I ended up rolling off my own version of that but due to my timings, my count is more like 32x a second, but that's ok.
I'm going to explain what I did first so everyone understands what is going on.
code explanation
I have four consecutive address locations setup to point to values of counters for each bit. Four bits are read simultaneously from hardware and a counter for that bit goes up or down based on whether that bit is set (light detected on that group of sensors) or clear (light not detected). This loop executes frequently at about a 9600bps speed.
The second loop only executes when a value is needed. This happens once every 16 times that the last loop executes (more like at a 600bps speed). It takes the counter value of each bit as if it was a signed number and uses the MSB value as the final value of that bit. Those MSB values get crammed together to form the official bit read from the sensors.
Is this approach OK to reliably determine whether the bit value is set or cleared?
And could I somehow redo this code so the processes run faster? because each loop consumes a large number of clock cycles (32 to 40) and if I can get it down to maybe 20 clock cycles, I'd be happy.
Also, this code is executed on AT89S52 microcontroller so I'm using its extended memory addresses.
the code
;memory is preinitialized to nulls
LAZMAJ equ 0E0h ;majority counters start address (end address at 0E4h)
MAJT equ 20h ;Majority value at bit address
mov A,P0 ;get bit values from hardware
mov R1,#LAZMAJ ;go to start of pointer
;loop uses 40 clock cycles out of 192 available
countmaj:
rrc A ;get bit
jnc noincmaj
inc #R1 ;bit is set so add 1 to counter for that bit
noincmaj:
jc incmaj
dec #R1 ;bit is clear so subtract 1 from counter for that bit
incmaj:
inc R1 ;move pointer to next bit
cjne R1,#LAZMAJ+4,countmaj ;see if pointer is out of range
;it is so end loop
;loop uses about 32 clock cycles and executes when we want data
mov R1,#LAZMAJ+4 ;go to out of range position
chkmaj:
dec R1 ;decrement pointer first so we are within range
mov MAJT,#R1 ;load value to majority variable. treat it as signed
mov #R1,#0h ;clear value from memory space
mov C,MAJT.7 ;Take sign and use that as carry
rlc A ;and put it into our final variable
cjne R1,#LAZMAJ,chkmaj ;if pointer isn't in first address then keep going
;otherwise exit loop and A=value we want
I was looking at answers in Simple serial point-to-point communication protocol and it doesn't help me enough with my issue. I am also trying to communicate data between a computer and an 8-bit microcontroller at first, then eventually I want to communicate the one microcontroller to about 40 others via wireless radio modules. Basically one is designated as a master and the rest are slaves.
speed is an issue
The issue at hand is speed. because communication of every packet needs to be done at least 4x a second back and forth between the master and each slave.
Let's assume baud rate for data is 9600bps. That's 960 bytes a second.
If I used 16-byte packets then: 40 (slaves) times 16 (bytes) times 2 (ways) = 640. Divide that into 960 and that would mean well more than 1/2 a second. Not good.
If I used 8-byte packets then: 40 (slaves) times 8 (bytes) times 2 (ways) = 320. Divide that into 960 and that would mean 1/3 second. It's so-so.
But the thing is I need to watch my baud because too high of baud might mean missed data at larger distances, but you can see the speed difference between an 8 and 16 byte packet.
packet format idea
In my design, I may have a need to transmit a number in the low millions so that will use 24-bits which fits in my idea. But here's my initial idea:
Byte 1: Recipient address 0-255
Byte 2: Sender address 0-255
Byte 3: Command
Byte 4-6: Data
Byte 7-8: 16-bit fletcher checksum of above data
I don't mind if the above format is adjusted, just as long as I have at least 6 bits to identify the sender and receiver (since I'll only deal with 40 units), and the data with command included should be at least 4 bytes total.
How should I modify my data packet idea so that even the device that just turned on in the middle of reception can be in sync with the next set of data? Is there a way without stripping a bit from each data byte?
Rely on the check sum! My packet would consists of:
Recipient's address (0..40) XORed with 0x55
Sender's address (0..40) XORed with 0xAA
Command Byte
Data Byte 0
Data Byte 1
Data Byte 2
CRC8 sum, as suggested by Vroomfondel
Every receiver should have a sliding window of the last seven received bytes. When a byte was shifted in, that window should checked if it is valid:
Are the two addresses in the valid range?
Is it a valid command?
Is the CRC correct?
Especially the last one should safely reject packets on which the receiver hopped on off-sync.
If you have less than 32 command codes, you may go down to six bytes per packet: 40[Senders] times 40[Receivers] times 32[Commands] evaluates to 51200, which would fit into 16 bits instead of 24.
Don't forget to turn off the parity bit!
Update 2017-12-09: Here a receiving function:
typedef uint8_t U8;
void ByteReceived(U8 Byte)
{
static U8 Buf[7]; //Bytes received so far
static U8 BufBC=0;
Buf[BufBC++] = Byte;
if (BufBC<7) return; //Msg incomplete
/*** Seven Byte Message received ***/
//Check Addresses
U8 Adr;
Adr = Buf[0] ^ 0x55; if (Adr >= 40) goto Fail;
Adr = Buf[1] ^ 0xAA; if (Adr >= 40) goto Fail;
if (Buf[2] > ???) goto Fail; //Check Cmd
if (CalcCRC8(Buf, 6) != Buf[6]) goto Fail;
Evaluate(...);
BufBC=0; //empty Buf[]
return;
Fail:
//Seven Byte Msg invalid -> chop off first byte, could use memmove()
Buf[0] = Buf[1];
Buf[1] = Buf[2];
Buf[2] = Buf[3];
Buf[3] = Buf[4];
Buf[4] = Buf[5];
Buf[5] = Buf[6];
BufBC = 6;
}
I know that addition of two unsigned integers larger than the bus size of a given processor can be achieved via the carry flag. And normally, the same is true for signed integers using the overflow flag. However, the Intel 8085 only possesses a Sign flag, not an Overflow flag, so how does it deal with signed integer arithmetic?
As you know, the overflow flag is only relevant for signed integer arithmetic. On processors whose ALU has both overflow and carry flags (like x86), both of these flags get set according to the result of a binary arithmetic operation, but it's up to the programmer to decide how to interpret them. Signed arithmetic uses the overflow flag; unsigned arithmetic uses the carry flag. Looking at the wrong one gives you meaningless data.
There are two cases where the overflow flag would be turned on during a binary arithmetic operation:
The inputs both have sign bits that are off, while the result has a sign bit that is on.
The inputs both have sign bits that are on, while the result has a sign bit that is off.
Basically, then, the overflow flag gets set when the sign bit of the result does not match the sign bit of the input operands. In all other cases, the overflow flag is turned off.
Taking a couple of examples:
0100 + 0001 = 0101 (overflow flag off)
0100 + 0100 = 1000 (overflow flag on)
0110 + 1001 = 1111 (overflow flag off)
1000 + 1000 = 0000 (overflow flag on)
1000 + 0001 = 1001 (overflow flag off)
1100 + 1100 = 1000 (overflow flag off)
Notice that the state of the overflow flag depends only on the sign bits of the three numbers; thus, you need only look at these bits. This makes intuitive sense. If you add two positive numbers to get a negative, then the answer must be wrong because two positive numbers should give a positive result. Conversely, if you add two negative numbers and get a positive number, that also must be wrong. A positive number added to a negative number can never overflow because the sum lies between the two input values. Thus, arithmetic of mixed-signed values never turns on the overflow flag.
(Obviously this all assumes two's-complement arithmetic.)
Thus, you can easily calculate the state of the overflow flag even if the processor's ALU doesn't do it for you automatically. All you need to do is look at the sign bits of the three values, specifically the binary carry into the sign bit and the binary carry out of the sign bit. Overflow occurs when a bit is carried into the sign-bit place and no corresponding carry out occurs.
These C functions implement the logic:
// For the binary (two's complement) addition of two signed integers,
// an overflow occurs if the inputs have the same sign AND ALSO the
// sign of the result is different from the signs of the inputs.
bool GetOverflowFlagForAddition(int op1, int op2, int result)
{
return (~(op1 ^ op2) & (op1 ^ result)) < 0;
}
// For the binary (two's complement) subtraction of two signed integers,
// an overflow occurs if the inputs have the same sign AND ALSO the
// sign of the result matches the signs of the inputs.
bool GetOverflowFlagForSubtraction(int op1, int op2, int result)
{
return ((op1 ^ op2) & (op1 ^ result)) < 0;
}
(There are many different ways that you could write this, of course.)
Or, to put it in the terms that Iwillnotexist Idonotexist did in a comment: "Overflow can be defined as the XOR of the carry into and out of the sign bit." Overflow has occurred if the carry in does not equal the carry out at that particular (leftmost) bit.
A more formal definition is that the overflow flag is the XOR of the carry-out of the high two bits of the result. Symbolically, for an 8-bit value: O = C6 ^ C7, where O means "overflow" and C means "carry". This is just a restatement of the definition I already gave: overflow happens if the carry out is different from the carry into the highest-order bit (in this case, bit 7).
See also Ken Shirriff's article on how the overflow flag works arithmetically (this is in the context of the 6502, another popular 8-bit processor). He also explains the implementation of the overflow flag at the silicon level in the 6502.
Okay, so what does the carry flag mean? The carry flag indicates an overflow condition in unsigned arithmetic. There are again two cases where it is set:
The carry flag is set during addition if there is a carry out of the most significant bit (the sign bit).
The carry flag is set during subtraction if there is a borrow into the most significant bit (the sign bit).
In all other cases, the carry flag is turned off. Again, examples:
1111 + 0001 = 0000 (carry flag on)
0111 + 0001 = 1000 (carry flag off)
0000 - 0001 = 1111 (carry flag on)
1000 - 0001 = 0111 (carry flag off)
Just in case it isn't obvious, it bears explicitly pointing out that subtraction is the same as addition of the two's-complement negation, so the latter two examples can be rewritten in terms of addition as:
0000 + 1111 = 1111 (carry flag on)
1000 + 1111 = 0111 (carry flag off)
…but note that the carry for subtraction is the inverse of the carry set by addition.
Putting all of this together, then, you can absolutely implement the overflow flag in terms of the carry and sign flags. The carry flag gets set if you have a carry out of the most-significant bit (the sign bit). The sign flag gets set if the result has its sign bit set, which means that there was a carry into the most-significant bit. By our definition of the overflow flag above, OF == CF ^ SF, because overflow is the carry coming out of the sign bit XORed with the carry coming into the sign bit. If the carry in does not equal the carry out, then signed overflow occurred.
Interestingly, though, Ken Shirriff's reverse-engineering of the 8085 processor shows that it does, in fact, have an overflow flag—it's just undocumented. This is bit 1 of the 8-bit flag status register. It is known as "V" and, as Ken explains here, is implemented in exactly the way discussed above, by XORing the carry into the most-significant bit with the carry out of the most-significant bit—C6 ^ C7, with these values coming directly from the ALU. (He also describes in the same article how the other undocumented flag, the "K" flag, is implemented in terms of the "V" flag and the sign flag, yielding a flag that is useful in signed comparisons, but a bit beyond the scope of this answer.)
I am going over the following past paper question:
Consider the 4-bit generator, G = 1001, and suppose that the data portion
of a bit stream to be transmitted prior to Cyclic Redundancy Check (CRC)
calculation is 11001001. Show the actual bit stream transmitted. Suppose
the leftmost bit in the transmitted bit stream is inverted due to noise on the
transmission link. Show that this error is detected at the receiver’s end.
I have calculated the CRC to be appended to the end of the transmission using XOR as follows:
11001001000
1001|||||||
----|||||||
0101|||||||
1001||||||
-----||||||
001000||||
1001||||
----||||
000001100|
1001|
----|
01010
1001
----
0011
So R = 011 is appended to the transmission and is what is sent.
For the second part of the question I do the same thing except due to the error the leftmost but is now 0 so:
01001001011
1001|||||||
----|||||||
1101|||||||
1001|||||||
----|||||||
01001||||||
1001||||||
----||||||
0000001011
1001
----
0010 therefore there is an error
Where do I go from here? if it is all zeroes do I stop? But this would mean there is no error...
01001001011
1001||||||
----||||||
0000001011
1001
----
0010 <- Error!