We connect the library to work with ATTiny2313 MK, as well as, the library of delay functions.
#include <tiny2313.h> #include <delay.h>
Next, we make the necessary macro substitutions, according to the schematic assignments of the MC ports. These substitutions are convenient because in the text of the program instead of, for example, PORTB.5, you can write getAD, which is more convenient. The compilation getAD will be interpreted as PORTB.5. So, the first substitution is the outputs for connecting the first (A) and fourth (D) setpoint switches. The second is for the second (B) and third (C). Next - the substitution to turn on the relay. And, finally, the Ctrl substitution not used in the program and in the model under consideration. It can not write.
#define getAD PORTB.5 #define getBC PORTB.4 #define RL PORTD.0 #define Ctrl PIND.2
Variables A, B, C are used to store the position number of the corresponding three switches and take values from 0 to 9.
unsigned char A,B,C;
The variable i is the current value of the number of a tenth of a minute (6 seconds), that is, the number of the minimum "tick" of the relay. The variable t is the number of tenths of minutes (ticks) obtained from the setpoint.
unsigned int i=0,t;
The main function of the program is presented below. In the first 6 lines I did not understand. They are formed using the auxiliary utility CodeWizadAVR and are associated with the presence of external quartz at 10 MHz.
void main(void) { #pragma optsize- CLKPR=0x80; CLKPR=0x00; #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif
The next two lines configure port B of our MK. According to the scheme, we put the lower 4 bits at the input, and the high ones at the output (PB7 is not used, and PB6 is useless, but, in theory, the output is output). Therefore, according to the principles of the MK configuration, which I will not expound, we write to the DDRB register the number 240 (F0 in hexadecimal notation). The initial output level is “1”, except for the unnecessary PB7. And just in case, we will connect MK “pull-up resistors” to the inputs, even though they are already installed in the circuit. For this, the PORTB register is set to 7F in hexadecimal notation.
PORTB=0x7F; DDRB=0xF0;
Port D is configured in the same way. All pins to the input, except for the two younger ones. "Pull-up resistors" at the input and initial output level "1" at the weekend - the same.
PORTD=0x7D; DDRD=0x03;
The following five lines relate to the configuration of one of the timers MK. This timer is sixteen-bit, that is, it provides counting up to 2 ^ 16 = 65536. The frequency of the count is determined by the clock frequency of the MC and the division ratio (one of five preset). In the described program, it was decided to count for 6 seconds (the minimum task step), then increase the variable i by 1 and reset the timer to the beginning of the account. In order to ensure the above, it is necessary to take the maximum division factor of 1024 and count to 58,594. The latter is not difficult to calculate. The frequency of MK - 10,000,000 Hz. Using the division ratio of 1024, the timer frequency will be equal to 10,000,000 / 1,024 = 9,765,625 Hz, and the period - 1024 / 10,000,000 = 0.0001024 seconds. Within 6 seconds, 6 / 0.0001024 = 58593.75 such periods will be laid out. This number is within the 16-bit timer, but it is not integer, so you have to round it up to 58594. At the same time, the error of our time relay will be insignificant: 58594-58593.75 = 0.25; 0.25 * 0.0001024 = 0.0000256; 0.0000256 * 999 = 0.0255744. That is, for the maximum possible time interval (99.9 min.) The inaccuracy of this time relay will be approximately 25.6 milliseconds, which is quite acceptable in practice. By the way, the manufacturer also specifies the error of the device, and our error will be no worse. Write the value 5 to the TCCR1B timer configuration register. Without going into details, this means that the timer starts and the division factor is 1024. Write the value 0 to the TCNT1 register. This register is 16-bit and divided into two 8-bit halves: the youngest (L ) and senior (H). It records the value from which the timer will count. We need to be counted from scratch. The OCR1A register is written to the value to which the timer will count, after which it will call the interrupt function. At this point, the execution of the main function of the program is interrupted, and the actions specified in the function of the interrupt will be executed. After working off the interrupt, the execution of the main function will continue. This value, as mentioned above, is 58594 (E4E2 in Hex notation). Since the OCR1A register is also divided into two halves, we write down the above in parts.
TCCR1B=0x05; TCNT1H=0x00; TCNT1L=0x00; OCR1AH=0xE4; OCR1AL=0xE2;
The next two lines configure interrupt resolution properly (do not go into details).
TIMSK=0x40; #asm("sei")
In the main cycle, a constant poll of the setpoint switches (according to the algorithm in the description of the circuit) occurs with the use of delays of 30 ms for correctness and stability of operation. By setting PORTB.5 to “0” (getAD = 0), we prepare the first switch. His conclusions are connected to port D MK to pins 6, 5, 4, 3. The direction is from junior to senior. That is, the low-order bit of the switch is connected to the relatively low-order bit (bit 3) of port D of the MC. Therefore, in order to receive information from the DK MK port about the position of the first switch, it is necessary to make a bitwise shift to the right by three positions (PIND >> 3), invert the received bits with the operation “~” (since the information will arrive at “0”, according to the diagram) and reset unnecessary high four bits of the resulting 8-bit value. The last operation is done by a logical bitwise multiplication of the result by the number 15 (00001111 in the binary representation). After this operation, variable A will be assigned the position value of the first switch. Next, the first switch is turned off, and the second and third are prepared. The value from the second switch to variable B is removed from port B of the MK in the same way, but without a shift operation, since the terminals of this switch are connected to the youngest pins of port B of the MK and also with the same direction. The information from the third switch to variable C is removed in the same way as from the first. After this, the second and third switches (getBC = 1) are “closed” and the set value (the number of tenths of minutes) from the three switches is calculated into the variable t.
while(1){ delay_ms(30); getAD=0; delay_ms(30); A=(~(PIND>>3)&15); delay_ms(30); getAD=1; getBC=0; delay_ms(30); B=(~PINB)&15; C=(~(PIND>>3)&15); delay_ms(30); getBC=1; t=100*A+10*B+C; } }
The comparison of this variable and the analogous real-time variable i occurs in the interrupt function.
interrupt [TIM1_COMPA] void timer1_compa_isr(void){ i+=1; if(i>=t){ RL=0; }else{ RL=1; } TCNT1H=0x00; TCNT1L=0x00; }
If the last variable exceeds the value to be set, the execution relay will be activated by “0” (RL = 0). Moreover, it will turn off if at the same time setting the switches with a value greater than that of the variable i. In the same interrupt function, the variable i is increased by 1 and the timer is reset to 0.
FUSE bits were written off from the MK and left unchanged. I analyzed them, everything is fine there.
