Міністерство освіти і науки України
Національний університет “Львівська політехніка”
Кафедра КСА
Звіт
до графічно-розрахункової роботи
з предмету «Програмування мікроконтролерів систем автоматики»
Варіант №19
Львів 2017
Мета графічно-розрахункової роботи:
закріпити отримані при вивченні даного курсу знання і навики програмування мікроконтролерів AVR мовою асемблер та мовою високого рівня Сі;
навчитися проектувати мікроконтролерні мережі на основі інтерфейсу RS-485 та розробляти для них протоколи обміну даними;
отримати навики розроблення клієнтських програм під Windows для реалізації зв’язку між персональним комп’ютером та мікроконтролером згідно інтерфейсу RS-232.
Короткі теоретичні відомості
Інтерфейс RS-232 був розроблений для забезпечення зв’язку між термінальним обладнанням та апаратурою передачі даних, використовуючи послідовний обмін двійковими даними.
Стандарт RS-232 був розроблений у 1969 році американською Асоціацією електронної промисловості, та після незначних поправок отримав назву RS-232С. У 1991 році була здійснена модифікація цього стандарту, після чого він отримав назву EIA/TIA-232E. Інша відома назва цього протоколу ITU V.24. Загально прийнятою назвою є EIA-232, або просто RS-232.
У стандарті передбачені асинхронний та синхронний режими обміну, однак переважна більшість пристроїв (наприклад ПК) працюють лише в асинхронному режимі.
RS-485 (інша назва EIA/TIA-485) – найпоширеніший стандарт фізичного рівня зв’язку (канал зв’язку + спосіб передачі сигналу). Цей інтерфейс забезпечує обмін даними між декількома пристроями по одній двопровідній лінії зв’язку в напівдуплексному режимі. Для каналу зв’язку вибирається вита пара.
В основі інтерфейсу RS-485 лежить принцип диференціальної (балансної) передачі даних. По одному дроті (умовно А) іде оригінальний сигнал, а по іншому (B) – його інверсна копія. Тобто, якщо на одному дроті «1», то на іншому «0», і навпаки. Тому між двома дротами витої пари завжди є різниця потенціалів»: при логічній «1» вона позитивна, а при «0» – негативна. Такий спосіб передачі забезпечує високу стійкість до синфазних перешкод (що діють на два дроти лінії одночасно).
Стандарт RS-485 описує лише фізичний рівень процедури обміну даними. Його основні задачі це:
перетворення вхідної послідовності «1» та «0» у диференціальний сигнал;
передача диференціального сигналу в симетричну лінію зв’язку;
підключення чи відключення передавача драйвера згідно сигналу верхнього протоколу обміну;
прийом диференціального сигналу з лінії зв’язку.
Решта особливостей обміну, синхронізації та квітування покладається на верхній протокол обміну, наприклад RS-232 чи ModBus.
RS-485 забезпечує передачу даних зі швидкістю до 10 Мбіт/сек. Максимальна дальність залежить від швидкості: при швидкості 10 Мбіт/сек максимальна довжина лінії – 120 метрів, при швидкості 100 Кбіт/сек – 1200 метрів.
Згідно зі специфікацією RS-485 на лінії можуть знаходитися до 32 прийомопередавачів, враховуючи узгоджуючі резистори (120 Ом). Це обумовлено вхідним опором приймача 12 КОм з боку лінії. Деякі мікросхеми драйверів мають підвищений вхідний опір, і тому дають можливість підключати до лінії більшу кількість пристроїв.
Завдання
Тема 1. Цифровий давач температури DS18B20.
«master»: ATmega164P, «slave»: ATmega32.
частота тактування МК 9.216 МГц, швидк. передачі 9600 Бод,
адреса задається за допомогою «піаніна»,
адреси МК: slave1 = 77, slave2 = 105,
інтервал опитування МК «slave» = 1,7 сек.,
давачі підключаються до виводів PD7, PB7
Код програми пристрою мовою асемблер
Master
//--------------------------------------------------------------------------------------------------------------------------------
#define F_CPU 9216000L
#define BAUD 9600
#define UBRRcalc (F_CPU/(BAUD*16L)-1)
#define BUF_SIZE 16
#define BUF_MASK (BUF_SIZE-1)
#define BUF1_SIZE 16
#define BUF1_MASK (BUF1_SIZE-1)
//--------------------------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <math.h>
#include <stdlib.h>
//--------------------------------------------------------------------------------------------------------------------------------
unsigned char BufOut[BUF_SIZE], StartBufOut = 0, EndBufOut = 0;
unsigned char Buf1Out[BUF_SIZE], StartBuf1Out = 0, EndBuf1Out = 0;
volatile unsigned char WaitRead = 0, WaitWrite = 0;
unsigned char Number = 0;
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART0_RX_vect)
{
unsigned char Temporary=UDR0;
WriteBufOut(Temporary);
}
//--------------------------------------------------------------------------------------------------------------------------------
void WriteBufOut(unsigned char value)
{
BufOut[EndBufOut++] = value;
EndBufOut &= BUF_MASK;
cli();
if(WaitRead == 0) UCSR1B |= 1<<UDRIE1; sei();
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART1_UDRE_vect)
{
PORTD |= 1<<PD4;
UCSR1B |= 1<<TXB81;
asm("nop");
UDR1 = BufOut[StartBufOut++];
StartBufOut &= BUF_MASK;
if(StartBufOut == EndBufOut || WaitRead == 1) UCSR1B &= ~(1<<UDRIE1);
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART1_TX_vect)
{ PORTD &= ~(1<<PD4); }
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART1_RX_vect)
{
unsigned char One;
One = UDR1;
WriteBuf1Out(One);
Number++;
if (Number == 4)
{
Number = 0;
WaitRead = 0;
if(StartBufOut != EndBufOut) UCSR1B |= 1<<UDRIE1;
}
}
//--------------------------------------------------------------------------------------------------------------------------------
void WriteBuf1Out(unsigned char value)
{
Buf1Out[EndBuf1Out++] = value;
EndBuf1Out &= BUF1_MASK;
cli();
if(WaitWrite == 0) UCSR0B |= 1<<UDRIE0;
sei();
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART0_UDRE_vect)
{
UDR0 = Buf1Out[StartBuf1Out++];
WaitWrite = 1;
StartBuf1Out &= BUF1_MASK;
if(StartBuf1Out == EndBuf1Out || WaitWrite == 1) UCSR0B &= ~(1<<UDRIE0);
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART0_TX_vect)
{ WaitWrite = 0; }
//--------------------------------------------------------------------------------------------------------------------------------
int main()
{
cli();
Init();
_delay_ms(3000);
sei();
while(1)
{ }
}
//--------------------------------------------------------------------------------------------------------------------------------
void Init()
{
DDRA = 0xFF;
PORTA = 0x00;
DDRB = 0xFF;
PORTB = 0x00;
DDRC = 0xFF;
PORTC = 0x00;
DDRD=0b11111010;
PORTD=0b00000101;
UBRR1L = (unsigned char)(UBRRcalc);
UBRR1H = (unsigned char)(UBRRcalc>>8);
UCSR1A = 0;
UCSR1C = (1<<UCSZ11) | (1<<UCSZ10) | (1<<USBS1);
UCSR1B = (1<<UCSZ12) | (1<<RXEN1) | (1<<TXEN1) | (1<<RXCIE1) | (1<<TXCIE1);
UBRR0L = (unsigned char)(UBRRcalc);
UBRR0H = (unsigned char)(UBRRcalc>>8);
UCSR0A=0
UCSR0B=(1<<RXCIE0) | (1<<TXCIE0) | (1<<RXEN0) | (1<<TXEN0);
UCSR0C=(1<<UCSZ01) | (1<<UCSZ00);
}
//--------------------------------------------------------------------------------------------------------------------------------
Slave
//--------------------------------------------------------------------------------------------------------------------------------
#define LCDdataPORT PORTA
#define LCDdataPIN PINA
#define LCDdataDDR DDRA
#define LCDcontrolPORT PORTB
#define LCDcontrolPIN PINB
#define LCDcontrolDDR DDRB
#define RS 0
#define RW 1
#define E 2
#define F_CPU 9216000L
#define BAUD 9600
#define UBRRcalc (F_CPU/(BAUD*16L)-1)
#define BUF_SIZE 4
#define BUF_MASK (BUF_SIZE-1)
//--------------------------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <math.h>
#include <stdlib.h>
#include "LCD_8.h"
#include "DS18B20.h"
//--------------------------------------------------------------------------------------------------------------------------------
OneWire OW1={&DDRD, &PIND, &PORTD, PD7};
OneWire OW2={&DDRB, &PINB, &PORTB, PB7};
char timer=0, address;
unsigned char BufferOUT[BUF_SIZE], StartBufOUT = 0, EndBufOUT = 0, Boof[4];
volatile unsigned char waitread = 0, write = 0;
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART_RXC_vect)
{
if (UDR == address)
{
WriteBufOUT(Boof[0]);
WriteBufOUT(Boof[1]);
WriteBufOUT(Boof[2]);
WriteBufOUT(Boof[3]);
UCSRA &= ~(1<<MPCM);
UCSRB |= 1<<UDRIE;
write = 1;
}
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART_UDRE_vect )
{
PORTD |= 1<<PD2;
asm("nop");
UDR = BufferOUT[StartBufOUT++];
StartBufOUT &= BUF_MASK;
if( StartBufOUT == EndBufOUT )
{
UCSRB &= ~(1<<UDRIE);
UCSRA |= (1<<MPCM);
write=0;
}
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(USART_TXC_vect )
{
if( StartBufOUT == EndBufOUT ) PORTD &= ~(1<<PD2);
}
//--------------------------------------------------------------------------------------------------------------------------------
ISR(TIMER0_COMP_vect)
{
timer++;
if (timer==40)
{
timer=0;
unsigned int tempHB, tempLB, temp;
unsigned char tempDigital,tempDecimal, minus = 0;
char Sbuf[4];
Clear_LCD();
if(OneWireReset(OW1))
{
OneWireWriteByte(OW1, SKIP_ROM);
OneWireWriteByte(OW1, READ_SCRATCHPAD);
tempLB = (unsigned int)OneWireReadByte(OW1);
tempHB = (unsigned int)OneWireReadByte(OW1);
Boof[0]=(unsigned char) tempLB;
Boof[1]=(unsigned char) tempHB;
temp = (tempLB)|(tempHB<<8);
if(temp&0x8000)
{
temp = ~temp + 1;
minus = 1;
}
GotoXY(0, 0);
if(minus) Set_Char('-');
else Set_Char('+');
tempDigital = temp >> 4;
tempDecimal = temp & 0xF;
tempDecimal = (tempDecimal<<1) + (tempDecimal<<3);
tempDecimal = (tempDecimal>>4);
Set_String( utoa(tempDigital,Sbuf,10) );
Set_Char('.');
Set_String( utoa(tempDecimal,Sbuf,10) );
Set_Char('*');
Set_Char('C');
}
if(OneWireReset(OW1))
{
OneWireWriteByte(OW1, SKIP_ROM);
OneWireWriteByte(OW1, CONVERT_TEMP);
}
minus = 0;
if(OneWireReset(OW2))
{
OneWireWriteByte(OW2, SKIP_ROM);
OneWireWriteByte(OW2, READ_SCRATCHPAD);
tempLB = (unsigned int)OneWireReadByte(OW2);
tempHB = (unsigned int)OneWireReadByte(OW2);
Boof[2]=(unsigned char) tempLB;
Boof[3]=(unsigned char) tempHB;
temp = (tempLB)|(tempHB<<8);
if(temp&0x8000)
{
temp = ~temp + 1;
minus = 1;
}
GotoXY(0, 1);
if(minus) Set_Char('-');
else Set_Char('+');
tempDigital = temp >> 4;
tempDecimal = temp & 0xF;
tempDecimal = (tempDecimal<<1) + (tempDecimal<<3);
tempDecimal = (tempDecimal>>4);
Set_String( utoa(tempDigital,Sbuf,10) );
Set_Char('.');
Set_String( utoa(tempDecimal,Sbuf,10) );
Set_Char('*');
Set_Char('C');
}
if(OneWireReset(OW2))
{
OneWireWriteByte(OW2, SKIP_ROM);
OneWireWriteByte(OW2, CONVERT_TEMP);
}
}
}
//--------------------------------------------------------------------------------------------------------------------------------
void WriteBufOUT(unsigned char value)
{
if (write != 1)
{
BufferOUT[EndBufOUT++] = value;
EndBufOUT &= BUF_MASK;
}
}
//--------------------------------------------------------------------------------------------------------------------------------
int main()
{
Initial();
address = ~PINC;
if(OneWireReset(OW1) )
{
OneWireWriteByte(OW1, SKIP_ROM);
OneWireWriteByte(OW1, CONVERT_TEMP);
}
_delay_ms(1000);
if(OneWireReset(OW2) )
{
OneWireWriteByte(OW2, SKIP_ROM);
OneWireWriteByte(OW2, CONVERT_TEMP);
}
_delay_ms(1000);
sei();
while (1)
{ }
}
//--------------------------------------------------------------------------------------------------------------------------------
void Initial()
{
DDRA = 0xFF;
PORTA = 0x00;
DDRB = 0xFF;
PORTB = 0x00;
DDRC = 0x00;
PORTC = 0xFF;
DDRD=0b11111110;
PORTD=0b00000001;
UBRRL = (unsigned char)(UBRRcalc);
UBRRH = (unsigned char)(UBRRcalc>>8);
UCSRA = (1<<MPCM);
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)|(1<<USBS);
UCSRB = (1<<UCSZ2)|(1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE);
LCD_ini();
TCCR0 = (1<<WGM01)|(1<<CS02)|(1<<CS00);
OCR0 = 0x77;
TIMSK = (1<<OCIE0);
OneWireInit(OW1);
OneWireInit(OW2);
}
//--------------------------------------------------------------------------------------------------------------------------------
Клієнтська програма
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace rozr_v19
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool RS = false;
private void button2_Click(object sender, EventArgs e)
{
if (!RS)
{
serialPort1.Open();
button2.BackColor = Color.LimeGreen;
}
else
{
serialPort1.Close();
button2.BackColor = Color.Gainsboro;
}
RS = !RS;
}
bool DS = false;
private void button1_Click(object sender, EventArgs e)
{
if (!DS)
{
button1.BackColor = Color.LimeGreen;
}
else
{
button1.BackColor = Color.Gainsboro;
}
DS = !DS;
}
bool Slave = false;
byte[] boof = new byte[3];
private void timer1_Tick(object sender, EventArgs e)
{
if (DS && RS)
{
if (!Slave)
{
boof[0] = 77;
serialPort1.Write(boof, 0, 1);
int tempL1 = serialPort1.ReadByte();
int tempH1 = serialPort1.ReadByte();
int tempL2 = serialPort1.ReadByte();
int tempH2 = serialPort1.ReadByte();
short temp1 = (short)(tempL1 | (tempH1 << 8));
temp1 /= 16;
short temp2 = (short)(tempL2 | (tempH2 << 8));
temp2 /= 16;
label3.Text = "Temperature Outside = " + temp2.ToString() + "*C";
label4.Text = "Temperature Inside = " + temp1.ToString() + "*C";
}
else
{
boof[0] = 105;
serialPort1.Write(boof, 0, 1);
int tempL1 = serialPort1.ReadByte();
int tempH1 = serialPort1.ReadByte();
int tempL2 = serialPort1.ReadByte();
int tempH2 = serialPort1.ReadByte();
short temp1 = (short)(tempL1 | (tempH1 << 8));
temp1 /= 16;
short temp2 = (short)(tempL2 | (tempH2 << 8));
temp2 /= 16;
label5.Text = "Temperature Outside = " + temp2.ToString() + "*C";
label6.Text = "Temperature Inside = " + temp1.ToString() + "*C";
}
Slave = !Slave;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (RS) serialPort1.Close();
}
}
}
Скріншот клієнтської програми
/
Висновок: Отже, я закріпила отримані при вивченні даного курсу знання і навики програмування мікроконтролерів AVR мовою високого рівня Сі. Навчилася проектувати мікроконтролерні мережі на основі інтерфейсу RS-485 та розробляти для них протоколи обміну даними. Отримала навики розроблення клієнтських програм під Windows для реалізації зв’язку між персональним комп’ютером та мікроконтролером згідно інтерфейсу RS-232 мовою С#.
Принципова схема пристрою, що зібрана у пакеті Proteus
/