Thursday, June 26, 2014

Bài 3.(Học MSP430 qua ví dụ)Đồng hồ số - I2C ,Hiển thị giờ


1.      Hiển thị giờ
1.1.   Đọc ghi IC BQ32000
BQ32000 là 1 IC thời gian thực tương tự DS1307,để sử dụng được IC này chúng ta phải đọc Datasheet của nó.Về cơ bản IC này có chức năng giống như DS1307.Khi bắt đầu chương trình chúng ta cần tạo xung 1Hz xuất ra trên chân IRQ của BQ32000.Dùng xung này cho vào chân ngắt P1.0,chúng ta sẽ không phải liên tục đọc các thanh ghi của BQ32000 để xem sự thay đổi thời gian nữa,cứ mỗi ngắt của P1.1 thì tăng biến giây thêm,biến phút và giờ cũng vậy.Cứ sau 1 tiếng thì lại đọc lại các thông số thời gian để kiểm tra đề phòng trường hợp có nhiễu.


Đầu tiên bạn hãy download thư viện I2C_USCI.h,để sử dụng thư viện I2C cho giao tiếp BQ32000.Để hiểu rõ hơn về I2C của MSP430 ,các bạn đọc lại bài Tutorial 8 tại đây.Tiếp đến là add thư viện vào project và khai báo #include. Chúng ta thêm đoạn code khởi tạo vào hàm Initial().Đoạn code bao gồm hàm khởi tạo module I2C,Ngắt của MSP430 và tạo xung 1Hz của BQ32000.Cuối cùng là cho phép ngắt hoạt động.
            //Khoi tao BQ32000
#ifdef USE_UART
            UART_Write_Char(10);                     //Ky tu xuong dong
            UART_Write_String("Khoi tao RTC...");
#endif
            I2C_USCI_Init(BQ32000_ADDRESS);

            //Khoi tao ngat ngoai
#ifdef USE_UART
            UART_Write_Char(10);                     //Ky tu xuong dong
            UART_Write_String("Khoi tao ngat ngoai ...");
            UART_Write_Char(10);                     //Ky tu xuong dong
#endif
            P1REN |=BIT0;
            P1DIR&=~BIT0;
            P1IE |=BIT0;
            P1IES |=BIT0;
            P1IFG &=~BIT0;

            //Khoi tao che do xuat xung 1Hz cua BQ32000
            laplai:                           //Kiem tra xem da ghi duoc chua
            while(I2C_USCI_Write_Byte(0x07,0x40));
            if((I2C_USCI_Read_Byte(0x07)&0x40)!=0x40)goto laplai;
            while(I2C_USCI_Write_Byte(0x20,0x5E)); // Set thanh ghi dieu kien
            while(I2C_USCI_Write_Byte(0x21,0xC7)); // Set thanh ghi dieu kien
            while(I2C_USCI_Write_Byte(0x22,0x01)); // Set ngat 1Hz
            __bis_SR_register(GIE);                                //Cho phep ngat hoat dong

                Doc_thoi_gian();


Hàm đọc thời gian chúng ta sẽ tạo ngay dưới đây.
Tạo các biến toàn cục lưu thời gian,biến Dau_hai_cham để điều khiển dấu hai chấm nhấp nháy.
// Bien du lieu lay tu BQ32000
volatile unsigned char gio=0,phut=0,giay=0;
volatile unsigned char gio10BCD=0,gioBCD=0,phut10BCD=0,phutBCD=0;
volatile unsigned char ngay=0,thang=0,nam=0;
volatile unsigned char ngay10BCD=0,ngayBCD=0,thang10BCD=0,thangBCD=0;
volatile unsigned char Dau_hai_cham=0;

            Tiếp đó cần viết hàm đọc dữ liệu thời gian Doc_thoi_gian() từ BQ32000.Mục đích của việc này là để update dữ liệu thời gian khi khởi tạo,chuyển từ mã BCD (BQ3200 định dạng dữ liệu bằng mã BCD) thành decimal(các biến giay,phut,gio,ngay,thang,nam) ,và tách mỗi số ra thành 2 phần là hàng chục và hàng đơn vị(Các giá trị này chính là soled[…]).
void Doc_thoi_gian()
{
            unsigned char data[8];
            I2C_USCI_Read_Word(0x00,data,8);
            //Loai bo cac bit khong dung
            giay = data[1]&0x7F;
            phut = data[2]&0x7F;
            gio  = data[3]&0x3F;
            ngay = data[5]&0x3F;
            thang= data[6]&0x1F;
            nam  = data[7];

            //Chu y soled[10] se khong hien gi
            if(phut10BCD&0x70)phut10BCD = phut>>4;
            else phut10BCD = 10;            //Neu hang chuc = 0 thi khong hien thi
            phutBCD   = phut & 0x0F;

            if(gio&0x30)gio10BCD  = gio>>4;
            else gio10BCD=10;                //Khong hien thi
            gioBCD    = gio  & 0x0F;

            if(ngay&0x30)ngay10BCD=ngay>>4;
            else ngay10BCD=10;
            ngayBCD   = ngay&0x0F;

            if(thang&0x10)thang10BCD=thang>>4;
            else thang10BCD=10;
            thangBCD  = thang&0x0F;

            giay = (giay>>4)*10 + (giay & 0x0F);
            phut = (phut>>4)*10 + phutBCD;
            gio  = (gio>>4)*10  + gioBCD;
            ngay = (ngay>>4)*10 + ngayBCD;
            thang= (thang>>4)*10+ thangBCD;
            nam  = (nam>>4)*10  + (nam  & 0x0F);
#ifdef USE_UART
            UART_Write_Char(10);
            sprintf(buff,"ngay:%d thang:%d nam:20%d gio:%d phut:%d giay:%d",ngay,thang,nam,gio,phut,giay);
            UART_Write_String(buff);
            UART_Write_Char(10);         //Ki tu xuong dong
#endif
}


Khai báo ngắt của P1.0 .Chúng ta cần khai báo ngắt này trước khi test chương trình trên vì trong hàm Initial() đã thiết lập cờ cho phép ngắt và cài đặt ngắt trên chân P1.0 nếu không chương trình sẽ lỗi vì không có chương trình ngắt. 
#pragma vector = PORT1_VECTOR
__interrupt void Interrupt_PORT1(void)
{
            if(P1IFG&BIT0)
            {
                        P1IFG &=~BIT0;       //xoa co ngat tai chan P1.0
            }
}
           
            Đến đây các bạn có thể kiểm tra bằng Terminal xem đã đọc được dữ liệu chưa.Kết quả đọc IC BQ32000 được gởi qua UART trong hàm Doc_thoi_gian().Kết quả dạng thế này.
ngay:26 thang:6 nam:2014 gio:20 phut:50 giay:3


1.2.   Hiển thị LED



Ở bài trước chúng ta đã hiển thị được 1 số ra led 7 thanh.Bài này chúng ta sẽ viết hàm quét led Hien_thi_gio() .Thuật toán quét led khá đơn giản.Chúng ta sẽ thêm vào 2 biến để chỉnh độ sáng led.
// Bien dung cho hien thi led,chinh do sang led
unsigned char delay_led_on=240,delay_led_off=10;
             

          
Để một Led có thể sáng thì  một trong các chân led (14,11,7,10,6) phải ở mức logic 1,các chân này được nối trực tiếp vào VĐK ,mức logic ở các chân còn lại đã được xét trong phần quét GPIO.Để hiển thị 1 số thì mức logic ở chân ở chân nối với led đó phải ở mức logic 1(R1 ->R4) ,các chân còn lại ở mức logic 0.
                        Thuật toán :
-          Bật chân R1,ghi dữ liệu gio10BCD vào 74HC595.Led chục của giờ sẽ sáng,hiển thị gio10BCD.
-          Delay một khoảng delay_led_on.Đây chính là thời gian led sáng.
-          Ghi 0xFF và 74HC595.Tức là các led đều tắt.
-          Delay một khoảng delay_led_off.Đây là thời gian led tắt.Chúng ta sẽ phải tự tạo hàm delay,vì hàm _delay_cycles chỉ dùng được với tham số hằng,không thế dùng biến được.Cũng vì dùng hàm delay tự định nghĩa nên thời gian delay có thể không chính xác như hàm gốc.Tỉ lệ delay_led_on/delay_led_off sẽ cho ta mức sáng của led.Tổng thời gian 2 tham số này quyết định thời gian quét 1 led,4 lần số đó chính là thời gian quét led 1 lần.Phải đảm bảo tốc độ quét ít nhất 30 lần/s thì mới không thấy led nháy.Thực ra các bạn có thể thử trực tiếp để kiểm tra thời gian delay có đảm bảo led không nháy.Hoặc đo thời gian quét led để tính chính xác tốc độ quét(Có thể xem thêm trong bài Tutorial MSP430 Timer).
-          Tiếp theo làm tương tự với 3 led còn lại.Có thể chèn quét led dấu hai chấm vào 1 trong 4 led 7 thanh.
void Hien_thi_gio()
{
            GIO10_ON;
            if(Dau_hai_cham)P2OUT&=~BIT7; //Bat dau hai cham
            else P2OUT|=BIT7;    //Tat dau hai cham
            Write_74HC595_8bit(soled[gio10BCD]);
            _delay_us(delay_led_on);
            P2OUT|=BIT7;           //Tat dau hai cham
            Write_74HC595_8bit(0xFF);
            _delay_us(delay_led_off);

            GIO_ON;
            Write_74HC595_8bit(soled[gioBCD]);
            _delay_us(delay_led_on);
            Write_74HC595_8bit(0xFF);
            _delay_us(delay_led_off);

            PHUT10_ON;
            Write_74HC595_8bit(soled[phut10BCD]);
            _delay_us(delay_led_on);
            Write_74HC595_8bit(0xFF);
            _delay_us(delay_led_off);

            PHUT_ON;
            Write_74HC595_8bit(soled[phutBCD]);
            _delay_us(delay_led_on);
            Write_74HC595_8bit(0xFF);
            _delay_us(delay_led_off);
}

            Chỉnh lại hàm main để kiểm tra hàm Hien_thi_gio().
void main(void)
{
            Initial();
            while(1)
            {
                        Hien_thi_gio();
            }
}

Cuối cùng , để thực hiện chức năng đơn giản nhất là hiển thị giờ,chúng ta cần phải có khả năng update dữ liệu thời gian.Vì đã cài đăt xung 1Hz cho BQ32000.Chúng ta sẽ dùng hàm ngắt nhận xung 1Hz để thay đổi giá trị giờ,phút,giây.Dấu hai chấm sẽ thể hiện cho kim giây.

#pragma vector = PORT1_VECTOR
__interrupt void Interrupt_PORT1(void)
{
            if(P1IFG&BIT0)
            {
                        //Nhay dau cham
                        Dau_hai_cham ^=0x01;
                        if((phut==0)&&(giay==0))Doc_thoi_gian();
                        else if(giay<59)giay++;
                                    else
                                    {
                                                giay=0;
                                                if(phut<59)phut++;
                                                else
                                                {
                                                            phut=0;
                                                            if(gio<23)gio++;
                                                            else gio=0;
                                                }
                                    }

                        phut10BCD = phut/10;
                        phutBCD = phut%10;
                        if(gio<10)gio10BCD=10;       //Khong hien thi neu gio10BCD = 0
                        else gio10BCD = gio/10;
                        gioBCD = gio%10;

                        P1IFG &=~BIT0;       //Xoa co ngat tai chan P1.0
            }
}




            Khi chưa có hàm sửa thời gian,các bạn có thể khởi tạo hàm một lần khi debug bằng đoạn code sau,nhớ là chỉ chạy một lần thôi,để ghi dữ liệu vào bộ nhớ BQ32000.
            //Khoi tao thoi gian,chi lam 1 lan de dinh thoi gian
            /*
            I2C_USCI_Write_Byte(0x00,0x00);             //Giay
            _delay_cycles(10);
            I2C_USCI_Write_Byte(0x01,0x01);             //Phut
            _delay_cycles(10);
            I2C_USCI_Write_Byte(0x02,0x01);             //Gio
            _delay_cycles(10);
            */

            //Khoi tao thoi gian,chi lam 1 lan de dinh thoi gian
            /*
            I2C_USCI_Write_Byte(0x04,0x09);             //ngay
            _delay_cycles(10);
            I2C_USCI_Write_Byte(0x05,0x06);             //thang
            _delay_cycles(10);
            I2C_USCI_Write_Byte(0x06,0x0E);             //nam
            _delay_cycles(10);
            */


Toàn bộ chương trình chính:


Download code tại đây:Dong_ho_so_bai_3

Bài tiếp theo : Bài 4.(Học MSP430 qua ví dụ) Đồng hồ số - Tạo menu,viết các hàm chức năng

1 comment:

  1. Em không hiểu chỗ Các chân 14,11,10,6,8 anh chỉ em lại nguyên lý này được không dạ

    ReplyDelete

END COMMENT FACEBOOK-->