۱۴۰۱ بهمن ۲۲, شنبه

میکروکنترلر PIC - قسمت پنجم : واحد UART

 

microchip 16f877

اصول ارتباط سریال

دو روش عمده برای انتقال اطلاعات در سیستمهای کامپیوتری وجود دارد، انتقال موازی و انتقال سریال. در انتقال موازی اطلاعات بین کامپیوتر و وسیله ، طول کابل انتقال حداکثر به چند ده سانتیمتر محدود میشود، کابلها دارای چندیدن رشته سیم خواهند بود که عملا کاربرد این روش انتقال اطلاعات به موارد خاصی مثل چاپگرها و هارددیسک ها محدود شده است. در روش سریال دو وسیله میتوانند کیلومترها با هم فاصله داشته باشند و هیچ محدودیت فاصله ای در بین نیست.از تعداد کمتری سیم برای ارتباط ارتباط استفاده میشود و اطلاعات نه به صورت بایتی (مانند آنچه در روش موازی استفاده میشود) بلکه به صورت بیت به بیت منتقل میشوند.


میکروکنترلر اطلاعاتی را که برای فرستادن به بیرون آماده کرده است در فرمت های یک بایتی قرار میدهد. در صورتیکه روش ارسال اطلاعات موازی باشد به راحتی این یک بایت به صورت همزمان به گذرگاه 8 بیتی منتقل شده و به دستگاه مقصد منتقل میشوند. اما در ارتباط سریال داده را توسط یک شیفت رجیستر به بیتهای سریال تبدیل میکنند و پس از ارسال در دستگاه گیرنده توسط یک شیفت رجیستر دیگر ، بیتهای سریال به یک بایت تبدیل میشوند.
درکاربردهای ساده ی ما که فاصله نقش مهمی ندارد دیتا بدون تغییر ارسال میشود،در فواصل دورتر باید ابتدا داده توسط مدولاتور مدوله شود و سپس ارسال شود . در دستگاه گیرنده هم داده ابتدا دمدوله شود تا قابل استفاده باشد.
در این آموزش ما از روش ارتباط آسنکرون استفاده خواهیم کرد. به این معنی که هیچ سیگنال همزمان کننده برای همزمان سازی انتقال اطلاعات با دیگر قسمتهای سیستم های سیستم وجود ندارد و انتقال اطلاعات تنها تابع سیگنالهای وقفه در حین اجرای برنامه یا تقاضای دیگر پریفرالها برای تبادل اطلاعات خواهد بود.
همچنین ارتباط مورد نظر full-duplex میباشد به این معنی که همزمان توانایی ارسال و دریافت داده توسط میکروکنترلر وجود دارد. در آینده ارتباطات سریال half-duplex مانند ارتباط از طریق پروتکل I2C بررسی خواهد شد.
سرعت ارتباط به صورت bps مخفف bit per second بیان میشود . در بعضی منابع از عبارت baud rate به معنی نرخ انتقال هم استفاده میشود که به جهت هماهنگی با بقیه متون ما نیز از این عبارت که بیشتر مربوط به مودم میباشد ، استفاده خواهیم کرد.سرعت ارنتقال هر دو دستگاه گیرنده و فرستند باید یکسان باشد، امروزه نرخ سرعت بین 1200bps 115200bps کاملا در دسترس میباشند . معمولا دستگاههای قدیمی تر با داده هایی که از حساسیت کمتر برخوردارند، از نرخ ارسال کمتر (مثلا 9600 bps) استفاده میکنند. بعضی از دستگاهها (مانند بعضی ماژول های GSM) نرخ ارسال دیتا توسط فرستنده را محاسبه کرده و خود را با آن وفق میدهند.


قالب بندی

در ارتباط به روش آسنکرون هر بایت دیتا بین بیتهای آغاز و پایان قرار میگیرد به این صورت که بیت آغازین همیشه 0 است و بیت (های) پایانی همیشه 1 هستند. همچنین تنها یک بیت آغاز وجود دارد اما بیت پایانی میتواند یک بیت یا دو بیت باشد.در هنگام ارسال ابتدا بیت آغازین سپس LSB و سپس بیتهای کم ارزشتر بعدی ارسال میشوند و در انتها MSB و بیت (های) پایانی ارسال خواهند شد.



همانگونه که در شکل مشخص است هنگامی که ارسالی صورت نمیگیرد خط در حالت بالا قرار دارد و به آن mark گفته میشود.به قرار گرفتن خط در حالت 0 space گفته میشود.در حالت استاندارد یک داده هشت بیت به همراه یک بیت آغاز و یک بیت پایان و در مواردی به همراه یک بیت توازن قالب داده ارسالی را تشکیل میدهد. توازن میتواند زوج یا فرد باشد و یا قالب بدون بیت توازن ارسال شود .

استاندارد RS232

استاندارد RS232 د PC و بعضی از تجهیزات استفاده میشود، در این استاندارد سطوح ولتاژ1 منطقی بین 3- تا 25- قرار دارد و سطح ولتاژ 0 با 3+ تا 25+ مشخص میگردد. چون این استاندارد قبل از ظهور TTL تدوین شده است با استاندارد TTL همخوانی ندارد. برای اتصال RS232 به یک میکروکنترلر باید حتما از line Driver استفاده کنیم . تراشه MAX232 یک راه انداز خط معروف به شمار میرود.
با توجه به اینکه به راحتی میتوان از یک مبدل USb به سریال استفاده نمود و به پورت سریال کامپیوتر دسترسی داشت، نحوه استفاده از MAX232 عنوان نمیشود. در صورت نیاز نحوه سیم بندی مانند شکل زیر میباشد:



ارتباط تنها به سه رشته سیم نیاز دارد . که مانند شکل زیر میباشد ، در این ارتباط از عملیات HandShaking بین کامپیوتر و میکروکنترلر با هم یا میکروکنترلر و دستگاه جانبی با هم صرف نظر شده است:




رجیسترهای واحد UART

رجیستروظیفه
TXSTAرجیستر کنترل و وضعیت ارسال
RCSTAرجیستر کنترل و وضعیت دریافت
SPBRGتولید Baud Rate
TXREGرجیستر ارسال/نگهداری اطلاعاتی که باید از طریق UART ارسال شوند.
RCREGرجیستر دریافت/ نگهداری اطلاعاتی که از طریق UART دریافت شده اند.

رجیستر TXSTA برای انتخاب مد سنکرون یا آسنکرون، سایز قالب و نوع قالب بندی داده ها استفاده میشود.

TXSTA
76543210
CSRCTX9TXENSYNC-BRGHTRMTTX9D

CSRC: انتخاب منبع پالس ساعت
        در مد اسنکرون بلا استفاده است.

TX9:فعال سازی ارسال 9 بیتی
        1: ارسال 9 بیتی
        0:ارسال 8 بیتی

TXEN:بیت فعالسازی ارسال
        1:ارسال فعال است
        0:ارسال غیر فعال است

SYNC:بیت انتخاب مد USART
        1:مد سنکرون
        0:مد آسنکرون

BRGH:بیت انتخاب Baud Rate با سرعت بالا
        1:انتخاب سرعت بالا
        0:انتخاب سرعت پایین (پیش فرض)

TRMT:وضعیت شیفت رجیستر ارسال
        1:TSR خالی است
        0:TSR پر است

TXD9:بیت نهم از دیتا که در فریم 8 بیتی میتواند به عنوان پریتی استفاده شود.


رجیستر RCSTA جهت تنظیم کنترل فرآیند دریافت استفاده میشود.

RCSTA
76543210
SPENRX9SRENCRENADDENFERROERRRX9D

SPEN:فعال سازی پورت سریال
         1:پورت سریال را فعال میکند و پایه های TX و RX را تبدیل به پایه های پورت سریال میکند.
        0:پورت سریال را غیر فعال میکند.

RX9:فعالسازی دریافت 9 بیتی
        1:انتخاب دریافت 9 بیتی
        0:انتخاب دریافت 8 بیتی

SREN:بیت فعال سازی دریافت تکی
        در مد آسنکرون کاربردی ندارد.

CREN:بیت فعال سازی دریافت مداوم (کارکرد در مد آسنکرون)
        1:فعالسازی دریافت مداوم
        0:غیرفعالسازی دریافت مدارم

ADDEN:بیت فعالسازی آدرس
        1:فعالسازی آدرس و فعال سازی وقفه دریافت هنگامی که بیت RSR تنظیم شده باشد.
        0:غیر فعال کردن دریافت 9 بیتی . در این حالت بیت نهم برای پریتی میتواند استفاده شود.

FERR:بیت خطای قالب
        1:خطالب قالب بندی
        0:قالب بندی بدون خطا

OERR:بیت خطای تجاوز از محدوده
        1:خطای تجاوز اتفاق افتاده (با استفاده از پاک کردن بیت CREN میتواند پاک شود)
        0:خطای تجاوز اتفاق نیفتاده

TXD9:نهمین بیتی که دریافت میشود. درصورتیکه استفاده نشود باید 0 قرار گیرد . همچنین میتواند به عنوان بیت توازن به کار رود که محاسبات آن برعهده برنامه نویس است.


نحوه محاسبه BAUD RATE و تنظیم رجیستر SPBRG

یکی از شاخصه های ارتباط سریال نرخ ارسال و دریافت میباشد. الزاما این عدد باید برای فرستنده و گیرنده یکسال باشد تا ارتباط موفقی را شاهد باشیم.با استفاده از رجیستر SPBRG میتوان باود ریت دلخواه خود را تنظیم نمود در صورتیکه بیت BRGH در رجیستر TXSTA برابر به 0 باشد به ازای نرخ ارسال مشخص مقدار رجیستر SPBRG به صورت زیر محاسبه میگردد:

SPBRG = (Fosc / (64 * Baud rate)) - 1

در صورتیکه بیت BRGHبرابر با 1 باشد . ارتباط با سرعت 4 برابر بیشتر اتفاق میفتد و مقدار رجیستر SPBRG بر حسب باود ریت مورد نظر ما به صورت زیر محاسبه میشود:

SPBRG = (Fosc / (16 * Baud rate)) - 1

جداول زیر میتواند در بدست آوردن محدوده خطا در باود ریتهای مختلف راهگشا باشد:




مراحل ارسال یک کاراکتر از طریق UART

        1:انتظار برای اینکه کاراکتر قبلی ارسال شود بیت TXIF در این هنگام 1 شده و نشانگر خالی شدن رجیستر TXREG میباشد.
        2:پاک کردن بیت TXIF برای استفاده در سیکل بعدی ارسال کاراکتر
        3:بارگیری کاراکتر جدید برای ارسال در THR

کد زیر مراحل را نشان میدهد.
void UART_TxChar(char ch)
{
    while(TXIF==0);  // Wait till the transmitter register becomes empty
    TXIF=0;          // Clear transmitter flag
    TXREG=ch;        // load the char to be transmitted into transmit reg
}

مراحل دریافت یک کاراکتر از طریق UART

        1:انتظار برای رسیدن دیتا در رجیستر دریافت.در این هنگام بیت RCIF برابر یک شده و به عنوان پرچم وجود یک داده جدید در رجیستر RCREG عمل میکند.
        2:پاک کردن RCIF برای استفاده در سیکل دریافت بعدی
        3:خواندن محتویات رجیستر RCREG

char UART_RxChar()
{
    while(RCIF==0);    // Wait till the data is received 
    RCIF=0;            // Clear receiver flag
    return(RCREG);     // Return the received data to calling function
}

تنظیم رجیسترهای UART

برای تنظیم واحد UART در مد آسنکرون و طول فریم 8 بیتی به همراه 1 بیت پایان و بدون بیت پریتی به صورت زیر عمل میکنیم:

void UART_Init(int baudRate)
{    
    TRISC=0x80;            // Configure Rx pin as input and Tx as output  
    TXSTA=(1<< SBIT_TXEN);  // Asynchronous mode, 8-bit data & enable transmitter
    RCSTA=(1<< SBIT_SPEN) | (1<< SBIT_CREN);  // Enable Serial Port and 8-bit continuous receive
    SPBRG = (16000000UL/(long)(64UL*baudRate))-1;      // baud rate @16Mhz Clock
}

        1:ابتدا پایه RX را بصورت ورودی و پایه TX را بصورت خروجی پیکربندی میکنیم.
        2:بیت پنجم از رجیستر TXSTA را برابر 1 میکنیم . در این حالت واحد فرستنده بصورت 8 بیتی بدون پریتی قالب بندی میشود.
        3:بیتهای چهارم و هفتم از رجیستر RCSTA را یک میکنیم . در این حالت واحد دریافت بصورت 8 بیتی بدون پریتی تنظیم میشود.
        4:رجیستر SPBRG را با عدد مناسب بارگذاری میکنیم.

مثال استفاده از کدهای فوق

برنامه زیر نحوه استفاده از توابع فوق را نشان میدهد.

/*
 * File:   uart.c
 * Author: Ali
 *
 * Created on July 18, 2017, 4:20 AM
 */

#define _XTAL_FREQ 16000000

#include < xc.h>
#include < pic16f877a.h>

// BEGIN CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//END CONFIG

#define SBIT_TXEN     5
#define SBIT_SPEN     7
#define SBIT_CREN     4


void UART_Init(int baudRate)
{    
    TRISC=0x80;            // Configure Rx pin as input and Tx as output  
    TXSTA=(1<< SBIT_TXEN);  // Asynchronous mode, 8-bit data & enable transmitter
    RCSTA=(1<< SBIT_SPEN) | (1<< SBIT_CREN);  // Enable Serial Port and 8-bit continuous receive
    SPBRG = (16000000UL/(long)(64UL*baudRate))-1;      // baud rate @16Mhz Clock
}


void UART_TxChar(char ch)
{
    while(TXIF==0);    // Wait till the transmitter register becomes empty
    TXIF=0;            // Clear transmitter flag
    TXREG=ch;          // load the char to be transmitted into transmit reg
}


char UART_RxChar()
{
    while(RCIF==0);    // Wait till the data is received 
    RCIF=0;            // Clear receiver flag
    return(RCREG);     // Return the received data to calling function
}


int main()
{
    char i,a[]={"Welcome to Pic Serial Comm, Type the char to be echoed: "};
    char ch;

    UART_Init(9600);          //Initialize the UART module with 9600 baud rate
    for(i=0;a[i]!=0;i++)
    {
        UART_TxChar(a[i]); // Transmit predefined string
    }

    while(1)
    {
        ch = UART_RxChar(); // Receive a char from serial port
        UART_TxChar(ch);    // Transmit the received char
    }
}




استفاده از وقفه دریافت

برنامه ای که تا اینجا بررسی شد، از روش polling برای بهره گیری از UART استفاده میکرد.به این معنی که میکرو همواره در انتظار دریافت یک کاراکتر از ورودی است و توانایی انجام کار دیگری ندارد. در روش استفاده از وقفه ، میکرو به کارهای روتین خود رسیدگی میکند و در هنگام تقاضا برای دریافت از طریق پورت سریال و واحد uart یک وقفه به میکرو اعمال میشود. در این هنگام میکرو کارهای روتین خود را کنار گذاشته، محتویات رجیسترهای کنترلی را در پشته قرار میدهد و با پرش به روتین وقفه ، به وقفه رسیدگی میکند. در انتها محتویات رجیسترها از پشته دریافت شده و میکرو به ادامه کار قبلی میپردازد
برای استفاده از وقفه دریافت باید حتما وقفه سراسری و وقفه پریفرالها فعال باشد. بیت وقفه دریافت نیز باید فعال باشد.قبل از تابع main روتین وقفه معرفی شود. به ساختار زیر توجه کنید :

#include < xc.h>
#include < pic16f877a.h>

// BEGIN CONFIG
#pragma config  PIC CONFIG
//END CONFIG
.
.
.
 void interrupt ISR(void);
 .
 .
 .
 int main(){
    UART_Init(9600);            //Initialize the UART module with 9600 baud rate

    PIE1bits.RCIE=1;            //Enable Recieve Interrupt
    
    INTCONbits.PEIE=1;          //Enable PEripheral Interrupt
    INTCONbits.GIE=1;           //Enable Global Interrupt
    .
    .
 }
 
 void interrupt ISR(void) {
        if (RCIF){
        RCIF=0; 
        .
        .
        
        }
}

با استفاده از وقفه ، برنامه دریافت از پورت سریال و فرستادن همان کاراکتر به پورت سریال را بازنویسی میکنیم:

/*
 * File:   uart.c
 * Author: Ali
 *
 * Created on July 18, 2017, 4:20 AM
 */

#define _XTAL_FREQ 16000000

#include < xc.h>
#include < pic16f877a.h>

// BEGIN CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
//END CONFIG

#define SBIT_TXEN     5
#define SBIT_SPEN     7
#define SBIT_CREN     4

void UART_Init(int baudRate)
{    
    TRISC=0x80;            // Configure Rx pin as input and Tx as output  
    TXSTAbits.TXEN = 1;  // Asynchronous mode, 8-bit data & enable transmitter
    RCSTA=(1<< SBIT_SPEN) | (1<< SBIT_CREN);  // Enable Serial Port and 8-bit continuous receive
    SPBRG = (16000000UL/(long)(64UL*baudRate))-1;      // baud rate @16Mhz Clock
}

void UART_TxChar(char ch){
    while(TXIF==0);    // Wait till the transmitter register becomes empty
    TXIF=0;            // Clear transmitter flag
    TXREG=ch;          // load the char to be transmitted into transmit reg
}

char UART_RxChar(){
    while(RCIF==0);    // Wait till the data is received 
    RCIF=0;            // Clear receiver flag
    return(RCREG);     // Return the received data to calling function
}

void interrupt ISR(void);
int main()
{
    

//char i,a[]={"Welcome to Pic Serial Comm, Type the char to be echoed: "};
//char ch; TRISD=0; UART_Init(9600); //Initialize the UART module with 9600 baud rate PIE1bits.RCIE=1; INTCONbits.PEIE=1; INTCONbits.GIE=1; while(1); return 0; } void interrupt ISR(void) { if (RCIF){ RCIF=0; UART_TxChar(RCREG); } }

هیچ نظری موجود نیست:

ارسال یک نظر