0-99 counter using one port ATMega32 - bascom

How to count from 0 to 99 using two 7SEG-BCD in proteus. I also tried to shift bits but i didn't succeed.
$regfile="m32def.dat"
$crystal=8000000
config portc = output
dim a as byte,b as byte
do
for a = 0 to 9
for b = 0 to 9
portc = makeint(a, b)
waitms 100
next
next
loop
end

Related

How to find the number of times a group of a specific value is present in an array?

I have a 1 by 1000 (1 row by 1000 columns) matrix that contain only 0 and 1 as their elements. How can I find how many times 1 is repeated 3 times consecutively.
If there are more than 3 ones then it is necessary to reset the counting. So 4 would be 3+1 and it counts as only one instance of 3 consecutive 1s but 6 would be 3+3 so it counts as two instances of having 3 consecutive 1s.
This approach finds the differences between when A goes from 0 to 1 (rising edge) and from 1 to 0 (falling edge). This gives the lengths of consecutive 1s in each block. Then divide these numbers by 3 and round down to get the number of runs of 3.
Padding A with a 0 at the start and end just ensures we have a rising edge at the start if A starts with a 1, and we have a falling edge at the end if A ends with a 1.
A = round(rand(1,1000));
% padding with a 0 at the start and end will make this simpler
B = [0,A,0];
rising_edges = ~B(1:end-1) & B(2:end);
falling_edges = B(1:end-1) & ~B(2:end);
lengths_of_ones = find(falling_edges) - find(rising_edges);
N = sum(floor(lengths_of_ones / 3));
Or in a much less readable 2 lines:
A = round(rand(1,1000));
B = [0,A,0];
N = sum(floor((find(B(1:end-1) & ~B(2:end)) - find(~B(1:end-1) & B(2:end))) / 3));
You can define your custom functions like below
v = randi([0,1],1,1000);
% get runs in cell array
function C = runs(v)
C{1} = v(1);
for k = 2:length(v)
if v(k) == C{end}(end)
C{end} = [C{end},v(k)];
else
C{end+1} = v(k);
end
end
end
% count times of 3 consecutive 1s
function y = count(x)
if all(x)
y = floor(length(x)/3);
else
y = 0;
end
end
sum(cellfun(#count,runs(v)))
Here is another vectorized way:
% input
n = 3;
a = [1 1 1 1 0 0 1 1 1 0 0 0 1 1 1 1 1 0 1 1 1 1 1 1 1]
% x x x x x = 5
% output
a0 = [a 0];
b = cumsum( a0 ) % cumsum
c = diff( [0 b( ~( diff(a0) + 1 ) ) ] ) % number of ones within group
countsOf3 = sum( floor( c/n ) ) % groups of 3
You like it messy? Here is a one-liner:
countsOf3 = sum(floor(diff([0 getfield(cumsum([a 0]),{~(diff([a 0])+1)})])/n))

How are the individual bits accessed in this code?

So I saw this code which printed out individual bits of any number.I do not understand why the individual bits are accessed and not the entire number itself
#include <stdio.h>
int main()
{
int x=10, b;
for(b=0; x!=0; x>>=1) {
printf("%d:%d\n", b, (x&1));
b++;
}
}
OUTPUT:
0:0
1:1
2:0
3:1
Please help me understand this piece of code.
In your code you are printing the value of X variable in binary. For this, your code, use logical operation as AND operator and right-shift.
In the loop condition, you displace the X variable one bit to the right.
for b = 0 you get x = 1010
for b = 1 you get x = 101
for b = 2 you get x = 10
for b = 3 you get x = 1
Then, in your print, show your loop iterator (b) and your X variable AND 1.
The AND operator get this values:
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
In your case, you have:
1010 AND (000)1 = 0
101 AND (00)1 = 1
10 AND (0)1 = 0
1 AND 1 = 1
There are two questions in your post: how to access an individual bit ? and how to select that bit ?
Concerning the first question, suppose you want to access the less significant bit (or, to make it simpler, the rightmmost bit), you can use a mask: suppose your data is b0011 for instance, you can mask with b0001 (i.e. 1 in decimal).
0 0 1 1
& 0 0 0 1
---------
0 0 0 1
The & operator is the bitwise and. If you look in your code sample, you have printf("%d:%d\n", b, (x&1)); in which you can see x & 1, i.e. print the rightmost bit of x.
Now comes the second question: how to put each bit in the rightmost position one after each other (said otherwise, how to select the bit to print) ? An easy solution is to shift your data of 1 position to the right each time you want to select the next bit (i.e. the bit to the left of the current one).
In C, you can shift using >>. For instance, if x is b0011, then x >> 1 is b0001 (in this case, you fill the leftmost position with zeros, but in some cases it might be trickier). If you look in you code sample, you have x>>=1 in the for-loop, which assigns x >> 1 in x.
Hence, suppose you take the previous example:
0 0 1 1 = x 0 0 0 1 = x
& 0 0 0 1 & 0 0 0 1
--------- x >> 1 = b0001 -> x ---------
0 0 0 1 0 0 0 1
and so one...
A last bonus point, the loop stopping condition is x != 0, this implies that you don't prints all bits of your data, but only the bits up to the leftmost 1 (included). For instance, in the above example, after printing the two rightmost bits, x becomes 0 and the loop exits.

How to make one second timer with atmega8?

I want make a one second timer with atmega8 and timer0. I used 8Mhz crystal and prescale = 1.
Every 125ns timer0 increases by one, so when timer0 overflows 31250 times, we should have one second, but it doesn't work properly and delays more then 5 seconds.
I used BascomAVR.
$regfile = "m8def.dat"
$crystal = 8000000
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6
,Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Timer0 = Timer , Prescale = 1
Dim Second As Word , Minute As Word , Hour As Word , Z As Integer
Second = 0
Minute = 0
Hour = 0
Z = 0
Enable Interrupts
Enable Timer0
Enable Ovf0
On Ovf0 Ovfroutin
Timer0 = 0
Start Timer0
Cursor Off
Cls : Home
Lcd "00:00:00"
Do
Loop
End 'end program
Ovfroutin:
Incr Z
If Z = 31250 Then
Stop Timer0
Z = 0
Incr Second
If Second = 60 Then
Second = 0
Incr Minute
If Minute = 60 Then
Minute = 0
Incr Hour
If Hour = 24 Then
Hour = 0
End If
If Hour < 10 Then
Locate 1 , 1
Lcd "0"
Locate 1 , 2
Else
Locate 1 , 1
End If
Lcd Hour
End If
If Minute < 10 Then
Locate 1 , 4
Lcd "0"
Locate 1 , 5
Else
Locate 1 , 4
End If
Lcd Minute
End If
If Second < 10 Then
Locate 1 , 7
Lcd "0"
Locate 1 , 8
Else
Locate 1 , 7
End If
Lcd Second
Start Timer0
End If
Timer0 = 0
Return

How to randomly pick a value based on the position of the bit

Is there a way to pick a value based on the bit position. The problem statement is:-
for a 16 bits position, I can set any bits, say I set 1,4,6,7,11,13 bit
so the mask would be:-
Bit Positons 0 0 1 0 1 0 0 0 1 1 0 1 0 0 1 0
Now I need to randomly pick a value based on this bit mask, where only 1 bit is set, so my possible values could be:-
For selecting 4 :0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
For Selecting 7: 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
But I need to select this value randomly, so I though of doing it like this
1)Create an Array based on the bit mask, so for 16 bit , the array would have 16 unique values.
2) Now do the rand operation on the array position to get the array index.
3) Use the value at that array index.
Is there a better way of doing it?
If I understand correctly you want a number with exactly one bit set that is also set in the mask.
To do this I'd make a while loop that selects a random value between 0 and 16 until it has found one that is also set in the mask:
uint16_t mask = 0x28d2; /* == 0 0 1 0 1 0 0 0 1 1 0 1 0 0 1 0 */
int bit = 0;
do{
bit = 1 << (rand() % 16); /* sets one random bit between 1 and 16 */
}while(!(mask & bit));
/* bit has now exactly one bit set that is also set in mask */
If the goal is to have a value with at most one bit set at the end, you don't need the array. You can simply randomly generate a value between 0-15, then bitshift 1 left by that value to get the mask that you will use to select the bit, like this:
uint16_t myValue = 0xA5;
int shiftValue = rand() % 16;
uint16_t randomMask = 1u << shiftValue;
uint16_t randomValue = myValue & randomMask;
If you instead need a value with exactly one of the bits set at the end, it gets a little trickier. At that point, you could do more or less what you said and use an array to store the positions of the bits that are set (e.g. [1, 4, 6, 7, 11, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], using zeroes to indicate when there are no more bits set), then generate a random index into the portion of the array containing valid indices. There are certainly other ways to do it too, but this way seems like one that will be fairly clear to future readers of the code (though I would still comment this somewhat carefully, since bit operations can get confusing fast).
(BTW, there are much better ways of generating random numbers than rand(), and you should probably use one of those if you need anything approaching real randomness - I just used it here as a convenient shorthand, since the actual RNG doesn't matter.)
You can do that in this way:
bitMask = 0x28d2;
randomNum = rand() % 16;
randomBit = (1<<randomNum) & bitMask;
If you want exactly one bit set, you could use a re-try loop, or something like this: (add the appropriate definitions and maybe add a special case for mask == 0)
while (mask)
{
array[i++] = mask & -mask;
mask &= mask - 1;
}
return array[rand_in_range(0, i)];
Where rand_in_range(a, b) is a function that returns a random number in the range [a, b> (be careful with that, 99% of the implementations of rand_in_range are incorrect while seeming correct in most tests, the worst kind of bug).

How to replace bits in a bitfield without affecting other bits using C

I wanted to replace bit/bits (more than one) in a 32/64 bit data field without affecting other bits. Say for example:
I have a 64-bit register where bits 5 and 6 can take values 0, 1, 2, and 3.
5:6
---
0 0
0 1
1 0
1 1
Now, when I read the register, I get say value 0x146 (0001 0 10 0 0110). Now I want to change the value at bit position 5 and 6 to 01. (Right now it is 10, which is 2 in decimal, and I want to replace it to 1 e 01) without other bits getting affected and write back the register with only bits 5 and 6 modified (so it becomes 126 after changing).
I tried doing this:
reg_data = 0x146
reg_data |= 1 << shift // In this case, 'shift' is 5
If I do this, the value at bit positions 5 and 6 will become 11 (0x3), not 01 (0x1) which I wanted.
How do I go about doing read, modify, and write?
How do I replace only certain bit/bits in a 32/64 bit fields without affecting the whole data of the field using C?
Setting a bit is okay, but more than one bit, I am finding it little difficult.
Use a bitmask. It is sort of like:
new_value = 0, 1, 2 or 3 // (this is the value you will set in)
bit_mask = (3<<5) // (mask of the bits you want to set)
reg_data = (reg_data & (~bit_mask)) | (new_value<<5)
This preserves the old bits and OR's in the new ones.
reg_data &= ~( (1 << shift1) | (1 << shift2) );
reg_data |= ( (1 << shift1) | (1 << shift2) );
The first line clears the two bits at (shift1, shift2) and the second line sets them.
Here is a generic process which acts on a long array, considering it a long bitfield, and addresses each bit position individually:
#define set_bit(arr,x) ((arr[(x)>>3]) |= (0x01 << ((x) & 0x07)))
#define clear_bit(arr,x) (arr[(x)>>3] &= ~(0x01 << ((x) & 0x07)))
#define get_bit(arr,x) (((arr[(x)>>3]) & (0x01 << ((x) & 0x07))) != 0)
It simply takes the index, uses the lower three bits of the index to identify eight different bit positions inside each location of the char array, and the upper remainder bits addresses in which array location does the bit denoted by x occur.
To set a bit, you need to OR the target word with another word with 1 in that specific bit position and 0 in all other with the the target. All 0's in the other positions ensure that the existing 1's in the target are as it is during OR, and the 1 in the specific positions ensures that the target gets the 1 in that position. If we have mask = 0x02 = 00000010 (1 byte) then we can OR this to any word to set that bit position:
target = 1 0 1 1 0 1 0 0
OR + + + + + + + +
mask 0 0 0 0 0 0 1 0
---------------
answer 1 0 1 1 0 1 1 0
To clear a bit, you need to AND the target word with another word with 0 in that specific bit position and 1 in all. All 1's in all other bit positions ensure that during AND the target preserves its 0's and 1's as they were in those locations, and a 0 in the bit position to be cleared would also set that bit position 0 in the target word. If we have the same mask = 0x02, then we can prepare this mask for clearing by ~mask:
mask = 0 0 0 0 0 0 1 0
~mask = 1 1 1 1 1 1 0 1
AND . . . . . . . .
target 1 0 1 1 0 1 1 0
---------------
answer 1 0 1 1 0 1 0 0
Apply a mask against the bitfield to maintain the bits that you do not want to change. This will also clear out the bits that you will be changing.
Ensure that you have a bitfield that contains only the bits that you want to set/clear.
Either use the or operator to "or" the two bitfields, or just simply add them.
For instance, if you wanted to only change bits 2 thru 5 based on input of 0 thru 15.
byte newVal = (byte)value & 0x0F;
newVal = (byte)value << 2;
oldVal = oldVal & 0xC3;
oldVal = oldval + newVal;
The question was about how to implement it in C, but as all searches for "replace bits" lead to here, I will supply my implementation in VB.NET.
It has been unit test tested. For those who are wondering what the ToBinaryString extension looks like: Convert.ToString(value,2)
''' <summary>
''' Replace the bits in the enumValue with the bits in the bits parameter, starting from the position that corresponds to 2 to the power of the position parameter.
''' </summary>
''' <param name="enumValue">The integer value to place the bits in.</param>
''' <param name="bits">The bits to place. It must be smaller or equal to 2 to the power of the position parameter.</param>
'''<param name="length">The number of bits that the bits should replace.</param>
''' <param name="position">The exponent of 2 where the bits must be placed.</param>
''' <returns></returns>
''' <remarks></remarks>'
<Extension>
Public Function PlaceBits(enumValue As Integer, bits As Integer, length As Integer, position As Integer) As Integer
If position > 31 Then
Throw New ArgumentOutOfRangeException(String.Format("The position {0} is out of range for a 32 bit integer.",
position))
End If
Dim positionToPlace = 2 << position
If bits > positionToPlace Then
Throw New ArgumentOutOfRangeException(String.Format("The bits {0} must be smaler than or equal to {1}.",
bits, positionToPlace))
End If
'Create a bitmask (a series of ones for the bits to retain and a series of zeroes for bits to discard).'
Dim mask As Integer = (1 << length) - 1
'Use for debugging.'
'Dim maskAsBinaryString = mask.ToBinaryString'
'Shift the mask to left to the desired position'
Dim leftShift = position - length + 1
mask <<= leftShift
'Use for debugging.'
'Dim shiftedMaskAsBinaryString = mask.ToBinaryString'
'Shift the bits to left to the desired position.'
Dim shiftedBits = bits << leftShift
'Use for debugging.'
'Dim shiftedBitsAsBinaryString = shiftedBits.ToBinaryString'
'First clear (And Not) the bits to replace, then set (Or) them.'
Dim result = (enumValue And Not mask) Or shiftedBits
'Use for debugging.'
'Dim resultAsBinaryString = result.ToBinaryString'
Return result
End Function
You'll need to do that one bit at a time. Use the or, like you're currently doing, to set a bit to one, and use the following to set something to 0:
reg_data &= ~ (1 << shift)
You can use this dynamic logic for any number of bit and in any bit field.
Basically, you have three parts in a bit sequence of number -
MSB_SIDE | CHANGED_PART | LSB_SIDE
The CHANGED_PART can be moved up to the extreme MSB or LSB side.
The steps to replace a number of bit(s) are as follows -
Take only the MSB_SIDE part and replace all the remaining bits with 0.
Update the new bit sequence by adding your desired bit sequence in particular position.
Update the entire bit sequence with LSB_SIDE of the original bit sequence.
org_no = 0x53513C;
upd_no = 0x333;
start_pos = 0x6, bit_len = 0xA;
temp_no = 0x0;
temp_no = org_no & (0xFFFFFFFF << (bit_len + start_pos)); // This is step 1
temp_no |= upd_no << start_pos; // This is step 2
org_no = temp_no | (org_no & ~(0xFFFFFFFF << start_pos)); // This is step 3`
Note: The masking with 0xFFFFFFFF is considered as 32 bit. You can change accordingly with your requirement.

Resources