Thông báo

Collapse
No announcement yet.

ATMEGA 8535 Giám sát hệ thống điều hòa + VB Source code + Firrmware source

Collapse
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • ATMEGA 8535 Giám sát hệ thống điều hòa + VB Source code + Firrmware source

    Đây là toàn bộ thiết kế bao gồm cả phần mềm và phần cứng của hệ thống giám sát dòng làm việc của cụm điều hòa không khí.

    Tôi xin đưa toàn bộ thiết kế này lên với một mong muốn chia sẻ một chút kinh nghiệm ít ỏi cho các bạn mới vào nghề có cơ sở tham chiếu để phát triển chúng thành những sản phẩm hữu ích hơn. Đồng thời cũng mong nhận được những trao đổi rút kinh nghiệm tù các bạn có trình cao trong nghề để cùng tiến bộ.

    I. GIỚI THIỆU.
    -Yêu cầu bài toán đặt ra là giám sát dòng điện làm việc và tính thời gian làm việc của điều hòa để có kế hoạch bảo trì hợp lý.
    -Có màn hình LCD hiển thị chế độ làm việc của cụm điều hòa hiện tại.
    -Có bàn phím đặt thông số như : Thời gian thực, giới hạn dòng điện nhỏ nhất, lớn nhất để cảnh báo của mỗi điều hòa trong cụm, bật tắt chế độ cảnh báo với điều hòa bất kỳ...
    -Khi điều hòa có hiện tượng quá tải hoặc thời hạn cần bảo trì thì cảnh báo cho người sử dụng bằng tín hiệu trên màn hình + còi...
    -Có thể kết nối bộ giám sát với máy tính để cài đặt thông số và xem số liệu.

    II. THỰC HIỆN.
    Hệ thống đã được tôi thực hiện như sau:
    -Đo dòng điện làm việc điều hòa bằng biến dòng gắn tại đầu vào của điều hòa.
    -Thiết kế bộ điều khiển bằng chíp ATMEGA8535 có 8 kênh vào ADC 10 bit để giám sát dòng điện của 8 điều hòa (lấy từ biến dòng).
    -Dùng màn hình LCD1602 để hiển thị tại chỗ.
    -Dùng 4 phím trạng thái để thao tác menu trên bộ điều khiển.
    -Viết phần mềm trên máy tính băng VB kết nối với bộ điều khiển qua cổng RS232 bằng giao thức MODBUS chuẩn.

    Các bài viết dưới đây tôi sẽ lần lượt đưa lên toàn bộ thiết kế để chúng ta cùng thảo luận.
    Last edited by sidesignvn; 16-11-2006, 11:34.
    Dùng hàng VN - Giữ lại USD cho đất nước.

  • #2
    1. Phần mềm máy tính.

    Hình chụp giao diện phần mềm:
    http://www.sidesignvn.com/downloads/...ADCardSoft.JPG

    Phần mềm đã biên dịch:
    http://www.sidesignvn.com/downloads/adcard/ADCard.exe

    Các bạn chú ý nếu máy tính đã cài VB thì chỉ cần download file .exe chạy luôn, nếu không các bạn lấy thêm thư viện MSCOMM32.OCX

    Mã nguồn của chương trình:
    http://www.sidesignvn.com/downloads/...ard-source.zip

    ------------
    Tôi không hiểu sao không thể Upload file lên điễn đàn để bài viết thêm sinh động đành phải gửi qua link khác, các bạn thông cảm. nếu ai biết lỗi tại sao thì chỉ giùm.
    Attached Files
    Last edited by sidesignvn; 17-11-2006, 10:25.
    Dùng hàng VN - Giữ lại USD cho đất nước.

    Comment


    • #3
      sao ko thấy bác cho lên cái firmsource code nhi?

      Comment


      • #4
        2. Thiết kế phần cứng.

        Files thiết bởi Protel99se:
        http://www.sidesignvn.com/downloads/.../adcardddb.zip

        Sơ đồ nguyên lý:
        Attached Files
        Last edited by sidesignvn; 16-11-2006, 17:26.
        Dùng hàng VN - Giữ lại USD cho đất nước.

        Comment


        • #5
          lại lắp cho BTS room hay Local exchange hả đồng chí? sorry nếu câu hỏi quá tò mò. bài này post lên với mục đích kinh tế, không phải là để học hỏi nên tôi đề nghị thu kinh phí để đóng góp cho thuê host cho diễn đàn.
          Last edited by Cuội; 16-11-2006, 19:08.

          Comment


          • #6
            Nguyên văn bởi Cuội Xem bài viết
            lại lắp cho BTS room hay Local exchange hả đồng chí? sorry nếu câu hỏi quá tò mò. bài này post lên với mục đích kinh tế, không phải là để học hỏi nên tôi đề nghị thu kinh phí để đóng góp cho thuê host cho diễn đàn.
            Tôi không biết nói sao với nội dung bài post này. Có lẽ để các anh em trên diễn đàn nhận xét.

            Và đây tôi xin tiếp tục công việc của mình.

            3. Thiết kế firmware.

            -Mã nguồn được thực hiện bằng CodeVision AVR. Chương trình bao gồm các module sau:
            Main.c
            File nguồn hực hiện các logic chính của chương trình như: Khởi tạo LCD, quét bàn phím, tổ chức menu, ...
            Code:
            /* Cac thu vien nap san */
            #include <mega8535.h>
            #include <stdlib.h>
            #include <stdio.h>
            #include <string.h>
            #include <delay.h>
            
            /* Cac tien dinh nghia va bien toan cuc */
            #define xtal 12000000L //Tan so giao dong thach anh
            #define true 1
            #define false 0
            #define RX_BUFFER_SIZE 32
            char sBuff[RX_BUFFER_SIZE]; //Bien tam khong su dung cho ngat
            
            #asm(".equ __lcd_port=0x15 ;PORTC")
            #define __lcd_port PORTC
            #define __lcd_direction DDRC
            #define __lcd_pin PINC
            #define __lcd_key_count 10000 //So lan quet phim de khang dinh 1 phim bam
            
            #include "incLcdKey.c"
            #include "incUARTpro.c"
            #include "incRTCpro.c"
            #include "incADC.c"
            #include "Modbus.h"
            
            unsigned char main_menu, sub_menu;
            bit input_mode;
            flash char menu_caption[6][16] 
            = {                    
            "",
            "1:WORK TIME",
            "2:ON SETTING",
            "3:HIGH SETTING",
            "4:ARLAM SETTING",
            "5:DATE & TIME"};
            
            flash char menu_title[6][8] 
            = {
            "",
            "H:M",
            "OnValue",
            "HiValue",
            "Arlam",
            ""};
            
            eeprom unsigned int work_time[8] = {1,1,1,1,1,1,1,1};
            eeprom unsigned char on_value[8] = {10,11,12,13,14,15,16,17};
            eeprom unsigned char hi_value[8] = {200,201,202,203,204,205,206,207};
            eeprom unsigned char arlam_status[8] = {1,1,1,1,1,1,1,1};
            eeprom unsigned char zone_delay = 5; //Thoi gian dung cho moi hien thi
            eeprom unsigned char menu_timeout = 30; //Thoi gian trong menu ma khong co phim bam
            
            unsigned char lcd_key_idle_time; //So giay ke tu thoi diem cuoi cung bam phim
            unsigned char value_temp,value_temp_old, zone_index,zone_index_count;
            
            void main_menu_show();
            void sub_menu_show();
            void sub_menu_edit();
            //long zone_value(unsigned char index);
            
            void FrameProcess(void);
            
            void main(void)
            {     
               unsigned int i, iMin, iMax, iData;
               unsigned char minute_old;
               bit OutputAlarmStatus, LedAlarmStatus;
               DDRD = 0xF0;
               PORTD.4 = true;
            	PORTD.5 = true;
            	PORTD.6 = true;
            	PORTD.7 = true;
            
               lcd_init(16,2);
               lcd_putsf("WELCOME!");
               InitTimer1();
               InitUART();
               InitADC();
               
               /* Global enable interrupts*/
               #asm("sei")        
               
               while (1)
               {
                  FrameProcess();
                        
            	   switch(lcd_getkey())
            	   {
            	      case 0: //Khong co phim bam
            	         if((time_changed) && (lcd_key_idle_time<255))
            	         {
            	            lcd_key_idle_time++;
            	            if((lcd_key_idle_time > menu_timeout) && (main_menu !=0)) 
                           {  main_menu = 0; sub_menu = 0;  input_mode = 0; }
                        }
            	         break;
            	      case 1: //Phim Esc
            	         lcd_key_idle_time = 0;
            	         if(main_menu == 0){} //Dang o goc
            	         else if(sub_menu == 0) main_menu = 0;//Dang o menu chinh
            	         else if(!input_mode) { sub_menu = 0; main_menu_show(); }//Dang o menu con
            	         else { input_mode = 0; sub_menu_show(); }//Dang o che do nhap lieu
            	         break;
            	      case 2: //Phim Ent               
            	         lcd_key_idle_time = 0;
            	         if(main_menu == 0) { main_menu = 1; main_menu_show(); }//Dang o goc
            	         else if(sub_menu == 0){ sub_menu = 1; sub_menu_show(); }//Dang o menu chinh
            	         else if(!input_mode)
            	         {  //
            	            if(main_menu != 1) 
            	            {
            	               input_mode = 1;
            	               if(main_menu == 2) value_temp = on_value[sub_menu-1];//Dat nguong duoi
            	               else if(main_menu == 3) value_temp = hi_value[sub_menu-1];//Dat nguong tren
            	               else if(main_menu == 4) value_temp = arlam_status[sub_menu-1];//Dat canh bao
            	               value_temp_old = value_temp;
            	               sub_menu_edit();
            	            }
            	         }
            	         else
            	         {  //Luu gia tri da thay doi vao EEPROM
            	            input_mode = 0;
            	            if(value_temp_old != value_temp)
            	            {
            	               if(main_menu == 2) on_value[sub_menu-1] = value_temp;//Dat nguong duoi
               	            else if(main_menu == 3) hi_value[sub_menu-1] = value_temp;//Dat nguong tren
            	               else if(main_menu == 4) arlam_status[sub_menu-1] = value_temp;//Dat canh bao
            	            }
            	            sub_menu_show();
            	         }
            	         break;
            	      case 4: //Phim giam
            	         lcd_key_idle_time = 0;
            	         if(main_menu == 0){}
            	         else if(sub_menu == 0)
            	         {  if(main_menu > 1) { main_menu--; main_menu_show(); }}
            	         else if(!input_mode) //
            	         {  if(sub_menu > 1) { sub_menu--; sub_menu_show(); } }
            	         else
            	         {
            	            if(main_menu == 2) //Dat nguong duoi
            	            {  if(value_temp > 1) value_temp -= 1;}
            	            else if(main_menu == 3) //Dat nguong tren
            	            {  if(value_temp > on_value[sub_menu-1]) value_temp -= 1;}
            	            else if(main_menu == 4) //Dat canh bao
            	               value_temp ^= 1; 
            	            else
            	            {
            	               if(sub_menu == 1) 
            	               {  if(t.year>2000) t.year--; }
            	               else if(sub_menu == 2) 
            	               {  if(t.month>1) t.month--; }
            	               else if(sub_menu == 3) 
            	               {  if(t.date>1) t.date--; }
            	               else if(sub_menu == 4) 
            	               {  if(t.hour>0) t.hour--; }
            	               else if(sub_menu == 5) 
            	               {  if(t.minute>0) t.minute--; }
            	               else if(sub_menu == 6) 
            	               {  if(t.second>0) t.second--; }
            	            }
            	            sub_menu_edit();
            	         } 
            	         break;  
            	      case 8: //Phim tang
            	         lcd_key_idle_time = 0;
            	         if(main_menu == 0){}
            	         else if(sub_menu == 0)
            	         {  if(main_menu < 5) { main_menu++; main_menu_show(); } }
            	         else if(!input_mode) //
            	         {  if(sub_menu < 8) { sub_menu++; sub_menu_show(); } }
            	         else
            	         {
            	            if(main_menu == 2) //Dat nguong duoi
            	               {if(value_temp < hi_value[sub_menu-1]) value_temp += 1;}
            	            else if(main_menu == 3) //Dat nguong tren
            	               {if(value_temp < 255) value_temp += 1;}
            	            else if(main_menu == 4) //Dat canh bao
            	               value_temp ^= 1;
            	            else
            	            {
            	               if(sub_menu == 1) 
            	               {  if(t.year<3000) t.year++; }
            	               else if(sub_menu == 2) 
            	               {  if(t.month<12) t.month++; }
            	               else if(sub_menu == 3) 
            	               {  if(t.date<31) t.date++; }
            	               else if(sub_menu == 4) 
            	               {  if(t.hour<23) t.hour++; }
            	               else if(sub_menu == 5) 
            	               {  if(t.minute<59) t.minute++; }
            	               else if(sub_menu == 6) 
            	               {  if(t.second<59) t.second++; }
            	            }
            	            sub_menu_edit();
            	         } 
            	         break;
            	   }
            
            	   if(time_changed) //Duoc dat = 1 do ngat thoi gian 1 giay.
            	   {
            	      time_changed = 0;
                     TimerUp(); //Tang bien thoi gian thuc
            	      
                     if(++zone_index_count >= zone_delay) //so giay chuyen hien thi mot lan
                        { zone_index_count = 0; if(zone_index++ >= 7) zone_index = 0;}
            	      if(main_menu == 0)                  
            	      {   
            	         lcd_clear();
            	         sprintf(sBuff,"%u ",t.date); //=19 bytes
            	         lcd_puts(sBuff);
            	         lcd_putsf(t_month_name[t.month-1]);
            	         sprintf(sBuff," %u:%u:%u",t.hour,t.minute,t.second);
            	         lcd_puts(sBuff);
            	         //printf(lcd_putchar,"%u %u:%u:%u",t.date,t.hour,t.minute,t.second);
            	         
            	         iMin = (int)on_value[zone_index] * 4;
            	         iMax = (int)hi_value[zone_index] * 4;
            	         iData = adc_data[zone_index];
            	         lcd_gotoxy(0,1);
            	         lcd_putsf("Zone(");
            	         if(iData < iMin) sprintf(sBuff,"%u):OFF",zone_index+1);
            	         else if(iData > iMax) sprintf(sBuff,"%u):ALRAM",zone_index+1);
                        else sprintf(sBuff,"%u):%u.%u(A)",zone_index+1,iData/40,iData%40);
            	         lcd_puts(sBuff);
            	      }
            	      else if((main_menu == 5) && (sub_menu == 0)) main_menu_show();
            	  
            	      OutputAlarmStatus = false;
            	      LedAlarmStatus = false;
            	      for(i=0;i<8;i++)                   
            	      {
            	         iMax = (int)hi_value[i] * 4;
            	         iMin = (int)on_value[i] * 4;
            	         if(adc_data[i] > iMax) 
            	         {
            	            if(arlam_status[i]) OutputAlarmStatus = true;
            	            else LedAlarmStatus = true;
            	         }
            	         if((minute_old != t.minute) && (iMin < adc_data[i])) work_time[i]++;
            	      }                                                               
            	      minute_old = t.minute;
            	      if(OutputAlarmStatus)
            	      {
            	         PORTD.4 = ~PORTD.4;
            	         PORTD.5 = ~PORTD.5;
            	         PORTD.6 = ~PORTD.6;
            	         PORTD.7 = ~PORTD.7;
            	      }
            	      else if(LedAlarmStatus)
            	      {  
            	         PORTD.4 = ~PORTD.4;
            	         PORTD.5 = ~PORTD.5;
            	         PORTD.6 = true;
            	         PORTD.7 = true;
            	      }
            	      else
            	      {
            	         PORTD.4 = true;
            	         PORTD.5 = true;
            	         PORTD.6 = true;
            	         PORTD.7 = true;
            	      }
            	   }  
            
               }
            }
            
            void main_menu_show()
            {           
               lcd_clear();
               lcd_putsf(menu_caption[main_menu]);
            	lcd_gotoxy(0,1);                   
            	if(main_menu != 5) lcd_putsf("----------------");
            	else
            	{
                  sprintf(sBuff,"%u/%u/%u-%u:%u:%u",t.date,t.month,t.year,t.hour,t.minute,t.second);
                  lcd_puts(sBuff);
            	}
            }
            
            void dt_menu_show(char c)
            {
               if(sub_menu == 1) sprintf(sBuff,"Year%c%u",c,t.year);
               else if(sub_menu == 2) sprintf(sBuff,"Month%c%u",c,t.month);
            	else if(sub_menu == 3) sprintf(sBuff,"Date%c%u",c,t.date);
            	else if(sub_menu == 4) sprintf(sBuff,"Hour%c%u",c,t.hour);
            	else if(sub_menu == 5) sprintf(sBuff,"Minute%c%u",c,t.minute);
            	else if(sub_menu == 6) sprintf(sBuff,"Second%c%u",c,t.second);
            	else sprintf(sBuff,"---");
            }
            
            void sub_menu_show()
            {
               lcd_clear();
            	lcd_putsf(menu_caption[main_menu]);
            	lcd_gotoxy(0,1);
               if(main_menu != 5)
               {
                  lcd_putsf(menu_title[main_menu]);
                  if(main_menu == 1) //Work time
            	      sprintf(sBuff,"(%u)<%u:%u>",sub_menu,work_time[sub_menu-1] / 60,work_time[sub_menu-1] % 60);
                  else if(main_menu == 2) //Dat nguong duoi
            	      sprintf(sBuff,"(%u):%u.%u",sub_menu,on_value[sub_menu-1]/10,on_value[sub_menu-1]%10);
                  else if(main_menu == 3) //Dat nguong tren
            	      sprintf(sBuff,"(%u):%u.%u",sub_menu,hi_value[sub_menu-1]/10,hi_value[sub_menu-1]%10);
                  else
            	      sprintf(sBuff,"(%u):%u",sub_menu,arlam_status[sub_menu-1]);
            	}
            	else dt_menu_show(':');
               lcd_puts(sBuff);
            }
            
            void sub_menu_edit()
            {  
               lcd_clear();
            	lcd_putsf(menu_caption[main_menu]);
            	lcd_gotoxy(0,1);                   
            	if (main_menu != 5)
            	{
            	   lcd_putsf(menu_title[main_menu]);
            	   if(main_menu == 4) //Dat canh bao
            	      sprintf(sBuff,"(%u)=%u",sub_menu,value_temp);
            	   else                                                                
            	      sprintf(sBuff,"(%u)=%u.%u",sub_menu,value_temp/10,value_temp%10);
               }
               else dt_menu_show('=');
            	lcd_puts(sBuff);
            }
            
            typedef struct 
            {
            unsigned int msb:1;
            unsigned int:14;
            unsigned int lsb:1;
            } bits;
            union doub {unsigned int i;char c[2];bits b;};
            
            unsigned int CRC16(char* lpMessage, unsigned char nSize)
            {
               // Khai bao bien:
               union doub sck,byt;
               unsigned int crc;
               unsigned char i,j;
               // Init:
            	sck.i=0xFFFF;
            	// Duyet tung BYTE trong vung nho:
            	for (i=0;i<nSize;i++)
               {
            	   byt.c[0]=lpMessage[i];
            		byt.c[1]=0;
            		sck.i^=byt.i;
            		for (j=0;j<8;j++)
            		{
            			if (sck.b.msb)
            			{
            				sck.i >>= 1;
            				sck.b.lsb=0;
            				sck.i^=0xA001;
            			} 
            			else
            			{
            				sck.i >>= 1;
            				sck.b.lsb=0;
            			}
            		}
            	}
            	crc = (sck.i)<<8;
            	crc |= (sck.i & 0xFF00) >> 8;
            	return crc;
            }
            
            void ModbusResponse(char *pChar)
            {          
               unsigned int CRC;
               unsigned char i;
               CRC = CRC16(&pChar[1],pChar[0]);
               pChar[++pChar[0]] = CRC>>8;
               pChar[++pChar[0]] = CRC&0xFF;
               for(i=1;i<=sBuff[0];i++) putchar(sBuff[i]);
            }
            
            void Int2pChar(int i, char* str) { str[0] = i>>8; str[1] = i&0xFF; }
            unsigned int pChar2Int(char* str)
            { 
               unsigned int i; 
               i = str[0];
               i <<= 8;
               i += str[1];
               return i; 
            }
            
            void SetDataIllegal(unsigned char ILLEGAL) //Set Data for Illegal Data Address
            {
               sBuff[0] = 3;
               sBuff[2] = CMD_EXCEPTION;
               sBuff[3] = ILLEGAL;
            }
            
            void RCS_Process()
            {  
               unsigned char i;  
               bit data_address_failed = false;
               if(sBuff[6]==8) 
               {
                  if(sBuff[4]==0)
                  { for(i=0;i<8;i++) if(arlam_status[i]) sBuff[4] += (1<<i); }
                  else data_address_failed = true;
               }                                      
               else data_address_failed = true;
               if(data_address_failed) SetDataIllegal(ILLEGAL_DATA_ADDRESS);
               else
               {
                  sBuff[3] = 1; //Byte Count
                  sBuff[0]=4; //Frame Byte Count
               }
               ModbusResponse(sBuff);
            }
            
            #define MAX_REGISTER 8
            #define INPUT_REGISTER_COUNT 8
            #define HOLDING_REGISTER_COUNT 40
            void RR_Process(unsigned char func)
            {  
               unsigned char i; 
               bit data_address_failed = false;
               if(sBuff[6]==8) 
               {
                  if(func == CMD_RHR)
                  {
                     if(sBuff[4]==0)
                     {  
                        Int2pChar(SAdd,&sBuff[4]);
                        Int2pChar(t.year,&sBuff[6]);
                        Int2pChar(t.month,&sBuff[8]);
                        Int2pChar(t.date,&sBuff[10]);
                        Int2pChar(t.hour,&sBuff[12]);
                        Int2pChar(t.minute,&sBuff[14]);
                        Int2pChar(t.second,&sBuff[16]);
                        Int2pChar(t.milisecond,&sBuff[18]);
                     }
                     else if(sBuff[4]==8) for(i=0;i<8;i++) Int2pChar(work_time[i],&sBuff[4+i*2]);
                     else if(sBuff[4]==16) for(i=0;i<8;i++) Int2pChar(on_value[i],&sBuff[4+i*2]);
                     else if(sBuff[4]==24) for(i=0;i<8;i++) Int2pChar(hi_value[i],&sBuff[4+i*2]);
                     else data_address_failed = true;
                  }
                  else //func = CMD_RHR
                  {
                     if(sBuff[4]==0) for(i=0;i<8;i++) Int2pChar(adc_data[i],&sBuff[4+i*2]);
                     else data_address_failed = true;
                  }
               }                                      
               else data_address_failed = true;
            
               if(data_address_failed) SetDataIllegal(ILLEGAL_DATA_ADDRESS);
               else
               {
                  sBuff[0]=19; //Frame Byte Count
                  sBuff[3]=16; //Modbus Data Byte Count
               }
               ModbusResponse(sBuff);
            }
            
            void PMR_Process(void)
            {
               unsigned char i;
               bit data_address_failed = false;
               if(sBuff[6]==8) 
               {
                     if(sBuff[4]==0)
                     {
                        SAdd = (unsigned char)pChar2Int(&sBuff[8]);
                        t.year = pChar2Int(&sBuff[10]);
                        t.month = (unsigned char)pChar2Int(&sBuff[12]);
                        t.date = (unsigned char)pChar2Int(&sBuff[14]);
                        t.hour = (unsigned char)pChar2Int(&sBuff[16]);
                        t.minute = (unsigned char)pChar2Int(&sBuff[18]);
                        t.second = (unsigned char)pChar2Int(&sBuff[20]);
                        t.milisecond = pChar2Int(&sBuff[22]);
                     }
                     else if(sBuff[4]==8) for(i=0;i<8;i++) work_time[i] = pChar2Int(&sBuff[8+i*2]);
                     else if(sBuff[4]==16) for(i=0;i<8;i++) on_value[i] = (unsigned char)pChar2Int(&sBuff[8+i*2]);
                     else if(sBuff[4]==24) for(i=0;i<8;i++) hi_value[i] = (unsigned char)pChar2Int(&sBuff[8+i*2]);
                     else data_address_failed = true;
               }                                      
               else data_address_failed = true;
            
               if(data_address_failed) SetDataIllegal(ILLEGAL_DATA_ADDRESS);
               else sBuff[0]=6; //Frame Byte Count
               ModbusResponse(sBuff);
            }
            
            void FMC_Process(void)
            {
               unsigned char i;  
               bit data_address_failed = false;
               if(sBuff[6]==8) 
               {
                  if(sBuff[4]==0)
                  {
                     for(i=0;i<8;i++) 
                     {
                        if((sBuff[8] & (1<<i)) && (arlam_status[i] == 0)) arlam_status[i] = 1; 
                        else if(!(sBuff[8] & (1<<i)) && (arlam_status[i] == 1)) arlam_status[i] = 0; 
                     }
                  }
                  else data_address_failed = true;
               }                                      
               else data_address_failed = true;
               if(data_address_failed) SetDataIllegal(ILLEGAL_DATA_ADDRESS);
               else sBuff[0]=6; //Frame Byte Count
               ModbusResponse(sBuff);
            }
                  
            void FrameProcess(void)
            {    
               unsigned char i;
               if (rx_frame_buffer_empty) return;
            	for(i=0;i<rx_frame_buffer[0];i++) sBuff[i] = rx_frame_buffer[i];
            	rx_frame_buffer_empty = 1;
               if (sBuff[1] == SAdd) // va xu ly CRC
               {  
                  if((sBuff[2]==CMD_RHR)||(sBuff[2]==CMD_RIR)) RR_Process(sBuff[2]);
                  else if(sBuff[2]==CMD_RCS) RCS_Process();
                  else if(sBuff[2]==CMD_PMR) PMR_Process();
                  else if(sBuff[2]==CMD_FMC) FMC_Process();
                  else 
                  {
                     SetDataIllegal(ILLEGAL_FUNCTION);
                     ModbusResponse(sBuff);
                  }
               }
            }
            incLcdKey.c
            File nguồn thực hiện khởi tạo LCD và bàn phím.
            Đây là mã nguồn được phát triển từ chương trình gốc của CodeVision, tôi có thay đổi và bổ xung để tận dụng chính cổng LCD để kiêm luôn nhiệm vụ quét bàn phím.
            incRTCpro.c
            File nguồn tổ chức đồng hồ thời gian thực của chương trình.
            Trong thiết kế này hệ thống có thể duy trì thời gian thực (năm,tháng, ngày, giờ ...) nếu có giải pháp duy trì không mất điện. Tuy nhiên tôi sử dụng thạch anh của hệ thống để tính thời gian nên sai số có thể lớn. Để phát triển giải pháp này chúng ta có thể dùng chíp thời gian chuyên dụng bên ngoài có pin CMOS duy trì...
            incADC.c
            File nguồn chứa thủ tục quét 8 đầu vào Analog.
            incuartpro.c
            File nguồn chứa các thủ tục truyền thông với máy tính.
            modbus.h
            File chứa các định nghĩa cho chuẩn truyền MODBUS.
            Việc diễn dải lệnh nằm trong chuờng trình chính Main.c

            Và đây là 100% mã nguồn của thiết kế:
            Attached Files
            Last edited by sidesignvn; 17-11-2006, 11:45.
            Dùng hàng VN - Giữ lại USD cho đất nước.

            Comment


            • #7
              III. LỜI KẾT.
              -Đây là thiết kế đã được tôi thực hiện nhưng nó chưa phải là một sản phẩm thực sự bởi nó được tạo ra bằng đam mê của chính tôi.
              -Với mong muốn được chia sẻ đam mê của mình với các bạn. Tôi mong rằng có ai đó có thể sử dụng thiết kế này và phát triển để nó trở thành hoàn thiện và có ứng dụng thực sự.
              Tôi sẵn sàng nhận góp ý và giúp các bạn về những vấn đề có liên quan qua diễn đàn này.

              Nào tiếp tục đi..............................
              Dùng hàng VN - Giữ lại USD cho đất nước.

              Comment


              • #8
                Đây là chủ để rất hay, chưa thấy ai lên tiếng nhỉ?
                Tôi có một số góp ý về phần cứng như sau:

                -LM741 có độ lệch điểm không cao, anh cần mắc vào đó biến trở chỉnh Offset giữa 2 chân 1 & 5.

                -Trong một trường hợp cụ thể như trên, nếu chỉ khuếch đại DC anh có thể thay bằng OPAM nguồn single như LM358, thậm chí dùng luôn nguồn cấp cho nó là +5V. Vậy cũng sẽ không cần diot Zener hạn áp phía sau. Anh cũng sẽ giảm được nguồn không mong muốn của anh là nguồn -9 V bằng phương pháp dao động và tách = Diot,C.

                -Một thiết kế khá nguy hiểm anh không để ý là việc dùng chung bus như không bảo vệ giữa keyboard và LCD. Nếu chỉ một phím bấm sẽ không vấn đề gì, nhưng 2 nút ấn đồng thời thì sẽ vô tình làm cấu nối chập 2 port của uC và nguy hiểm tại thời điểm Out dữ liệu ra LCD, có thể hỏng chân, chí ít cũng sai dữ liệu đk LCD. Vậy buộc anh phải có điện trở hạn dòng, hoặc dùng 4 diot, thêm nữa anh cần có một sự định thiên rõ ràng trạng thái không ấn phím thì lối ra sẽ nhận được gì? Theo tôi, anh ko nên dùng chung chân Backlight và chân keyboard chung nhau. Có một ít thông tin tại đây:
                http://www.dientuvietnam.net/forums/showthread.php?t=5

                -Theo tôi, anh không nên dùng chung nguồn giữa relay và uC. Đây là điều tối kỵ. Hơn nữa relay 5 V cũng hơi khó kiếm.

                -Kiểu mắc điều khiển IC driver 485 có vẻ chưa thật ổn: đó là anh chưa có Option điện trở đầu cuối, chưa có phần tử protect, phần chân điều khiển hướng của chúng thiết kế như vậy cũng gây sự giảm tốc độ truyền và khả năng gây lỗi. Phần IC đệm triger smitt dùng NOT cũng không cần thiết bởi tôi nhớ ko nhầm thì các IC driver như ds75176 đã có tính năng triger smitt rồi. Vậy thêm tâng đảo chỉ có tác dụng thêm tầng bảo vệ khi MAX485 bị hỏng, xác suất gây hỏng uC sẽ giảm nhờ tầng NOT này. Nhưng thực tế thì thoe kinh nghiệm của tôi, nếu IC driver 485 hỏng, rất ít có trường hợp các linh kiện theo sau hỏng.

                -Cũng là về rs485, việc mắc thêm tầng NOT sẽ gây một số phiền toái, ví dụ nếu anh nối vào PC cũng cần một mạch NOT như vậy tại bộ chuyển đổi RS232-485...

                Trên đây là một số góp ý của tôi, còn về phần Firmwave và VB tôi sẽ post tiếp khi có thời gian.

                Comment


                • #9
                  Thêm một vấn đề nữa là phần khuếch đại thuận tín hiệu lối vào OPAM, thấy các thông số chưa đầy đủ, việc chọn điện trở đầu vào của Opam cũng cần có giá trị thích hợp nếu không sẽ gây hiệu ứng âm đó.

                  Comment


                  • #10
                    Nhân đây, tui xin tham khảo một ý kiến về lập trình.
                    Nếu muốn khai báo một mảng bit thì có cách nào tối ưu. Hầu hết các trình dịch đều không cho khai báo mảng bit.
                    Vi dụ: bit a[10]; trình dịch không chấp nhận.
                    Nếu dùng byte thì phí quá

                    Comment


                    • #11
                      Rất cảm ơn những lời nhận xét của anh em trên diễn đàn.
                      Đúng là có nhiều vấn đề trong thiết kế này và tôi đã khắc phục như sau:

                      -Một thiết kế khá nguy hiểm anh không để ý là việc dùng chung bus như không bảo vệ giữa keyboard và LCD. Nếu chỉ một phím bấm sẽ không vấn đề gì, nhưng 2 nút ấn đồng thời thì sẽ vô tình làm cấu nối chập 2 port của uC và nguy hiểm tại thời điểm Out dữ liệu ra LCD, có thể hỏng chân, chí ít cũng sai dữ liệu đk LCD. Vậy buộc anh phải có điện trở hạn dòng, hoặc dùng 4 diot, thêm nữa anh cần có một sự định thiên rõ ràng trạng thái không ấn phím thì lối ra sẽ nhận được gì? Theo tôi, anh ko nên dùng chung chân Backlight và chân keyboard chung nhau.
                      Đã có 4 điện trở định thiên cho 4 phím rồi.
                      Còn chân backlight bình thường luôn có trạng thái "0" khi xuât dữ liệu ra LCD tôi đưa nó lên "1" để vô hiệu hóa bàn phím nên không có vấn đề gì vê xung đột cả, dẫu sao thời điểm viết dữ liệu ra LCD rất ngắn
                      Cái này BA nói hoàn toàn đúng để sửa lại thay vì 1 diot chúng ta sẽ dùng 4 diot như hình sau.
                      Attached Files
                      Last edited by sidesignvn; 04-12-2006, 11:04.
                      Dùng hàng VN - Giữ lại USD cho đất nước.

                      Comment


                      • #12
                        -Theo tôi, anh không nên dùng chung nguồn giữa relay và uC. Đây là điều tối kỵ. Hơn nữa relay 5 V cũng hơi khó kiếm.

                        -Kiểu mắc điều khiển IC driver 485 có vẻ chưa thật ổn: đó là anh chưa có Option điện trở đầu cuối, chưa có phần tử protect, phần chân điều khiển hướng của chúng thiết kế như vậy cũng gây sự giảm tốc độ truyền và khả năng gây lỗi. Phần IC đệm triger smitt dùng NOT cũng không cần thiết bởi tôi nhớ ko nhầm thì các IC driver như ds75176 đã có tính năng triger smitt rồi. Vậy thêm tâng đảo chỉ có tác dụng thêm tầng bảo vệ khi MAX485 bị hỏng, xác suất gây hỏng uC sẽ giảm nhờ tầng NOT này. Nhưng thực tế thì thoe kinh nghiệm của tôi, nếu IC driver 485 hỏng, rất ít có trường hợp các linh kiện theo sau hỏng.

                        -Cũng là về rs485, việc mắc thêm tầng NOT sẽ gây một số phiền toái, ví dụ nếu anh nối vào PC cũng cần một mạch NOT như vậy tại bộ chuyển đổi RS232-485...
                        Về vấn đề chung nguồn đúng là không tôt nếu rơle ăn dòng lớn. Trong thiết kế này tôi chỉ dùng có 2 rơle chắc chắn không gây ra vấn đề nhiễu nếu tụ lọc nguồn đủ lớn. Đã có thiết kế tôi dùng tới 16 rơle 5V chung nguồn với VXL nhưng chưa gặp vấn đề nhiễu nguồn.

                        Phần tử đảo có thể không có cũng được, nhưng để tương thích logic ta nên dùng nó (logic của 75176: khi ở chế độ rảnh đường truyền, chân A+ sẽ có logic "0" còn chân A- sẽ có logic "1" và 75176 ở chế độ nhận).
                        Còn việc làm chậm tốc độ truyền thì tôi vẫn chưa hiểu BA. Phải chăng vì dùng phần tử đảo có đặc tuyến trễ? Tôi cũng nghĩ đến vấn đề này nhưng vì tận dụng 2 phần tử của mạch rung điện áp âm nên phải dùng nó thôi. Với cách bố trí mạch này mình không cần phải điều khiển đường truyền đỡ tốn thêm 1 chân VXL chứ?
                        Bạn nào đã có thử nghiệm về tốc độ của mạch này thì cho anh em ý kiến nhé.
                        Dùng hàng VN - Giữ lại USD cho đất nước.

                        Comment


                        • #13
                          Nguyên văn bởi PPIICC Xem bài viết
                          Nhân đây, tui xin tham khảo một ý kiến về lập trình.
                          Nếu muốn khai báo một mảng bit thì có cách nào tối ưu. Hầu hết các trình dịch đều không cho khai báo mảng bit.
                          Vi dụ: bit a[10]; trình dịch không chấp nhận.
                          Nếu dùng byte thì phí quá
                          Tôi nghĩ rằng chẳng có cách nào để thực hiện mảng bít chuẩn đâu.
                          Thông thường trong một thiết kế mảng bit là có giới hạn nên tôi quy nó về số byte (mỗi byte chứa 8 bit) để chứa hết mảng đó và tạo ra 2 hàm cất giá trị bít và lấy lại giá trị bit ở một vị trí bất kỳ.
                          Dùng hàng VN - Giữ lại USD cho đất nước.

                          Comment


                          • #14
                            Nguyên văn bởi sidesignvn Xem bài viết
                            Về vấn đề chung nguồn đúng là không tôt nếu rơle ăn dòng lớn. Trong thiết kế này tôi chỉ dùng có 2 rơle chắc chắn không gây ra vấn đề nhiễu nếu tụ lọc nguồn đủ lớn. Đã có thiết kế tôi dùng tới 16 rơle 5V chung nguồn với VXL nhưng chưa gặp vấn đề nhiễu nguồn.

                            Phần tử đảo có thể không có cũng được, nhưng để tương thích logic ta nên dùng nó (logic của 75176: khi ở chế độ rảnh đường truyền, chân A+ sẽ có logic "0" còn chân A- sẽ có logic "1" và 75176 ở chế độ nhận).
                            Còn việc làm chậm tốc độ truyền thì tôi vẫn chưa hiểu BA. Phải chăng vì dùng phần tử đảo có đặc tuyến trễ? Tôi cũng nghĩ đến vấn đề này nhưng vì tận dụng 2 phần tử của mạch rung điện áp âm nên phải dùng nó thôi. Với cách bố trí mạch này mình không cần phải điều khiển đường truyền đỡ tốn thêm 1 chân VXL chứ?
                            Bạn nào đã có thử nghiệm về tốc độ của mạch này thì cho anh em ý kiến nhé.
                            -Số rơ le tối đa không quá quan trọng ở việc nhiễu nguồn mà phụ thuộc vào loại cuộn hút rơle, lí do chính ở đây chính là xung nhiễu khi đóng ngắt cuộn rơ le sinh ra dòng ngược khiến áp điện áp nguồn nạp vào tụ và đột ngột thay đổi. Tụ hóa có thể khử được nhiễu tần thấp nhưng với dập xung kim hơi khó. Có thể anh dùng tụ tatalium sẽ tốt hơn trong mạch. Theo tôi, các rơle cụ thể trong trường hợp anh dùng có thể được, nhưng với các rơ le khác thì cần cân nhắc, nó có thể khiến uC treo. Hơn nữa, nhiễu nguồn này có thể ít ảnh hưởng đến phần digital nhưng lại ảnh hưởng nhiều đến phần anlog đặc biệt là ADC nếu dùng vref trong.
                            -Về mạch RS485 thì khá nhiều thiết kế giống cách của anh, cách này có lợi điểm là không cần set tốc độ, sự xung đột bus về mặt vật lý khi có rủi ro N node mạng cùng truyền sẽ không sao. Về mặt vật lý nó gần như bus CAN. Lối ra có 2 trạng thái: hoặc ON hoặc Opencolecter(có trở định thiên kéo lên nguồn) nên lỡ có >=2 node cùng có tín hiệu trái dấu sẽ không sao về mặt vật lí và tín hiệu sẽ theo chiều bit trội (ON).
                            Với thiết kế của anh, khi chân điều khiển hướng DIR ở mức 1 thì không vấn đề gì, nhưng khi chân DIR ở mức 0 thì lối ra của ds75176 ở trạng thái trở kháng cao, mức áp trên đường dây lúc này phụ thuộc vào cặp điện trở anh định thiên. Vậy cặp điện trở này đóng vai trò khi mức logic này xảy ra chứ không phải phần driver của ds75176 đóng vai trò nữa. Bởi vậy, nếu trên đường dây có tụ ký sinh thì dẫn tới chậm tốc độ truyền hơn so với cách điều khiển chân DIR độc lập bằng 1 chân của uC hoặc dùng mạch đơn hài (555, 4538...). Nếu anh muốn cải thiện tốc độ, theo tôi, anh nên mắc cặp điện trở định thiên cỡ khá bé cỡ 470 ôm trên đường dây, tốt nhất chỉnh giá trị này đến điểm cân bằng sao cho sườn xung lên/xuống đều nhau. Nhưng như thế sẽ gây ra “nóng” cho IC driver bởi tải cặp điện trở “ ko cần thiết”.
                            Anh xem bảng logic sau sẽ rõ:
                            Rõ ràng là khi chân DIR = 0, mức áp trên bus không phụ thuộc vào phần driver của RS485 mà chỉ do điện trở định thiên. Thiết kế này vô tình chỉ dùng tới 1 nửa của phần Output ds75176.
                            Attached Files

                            Comment


                            • #15
                              Thiết kế chân điều khiển kiểu của anh sidesignvn dùng:
                              Kiểu này khiến phần driver là hở cực C.
                              Attached Files
                              -------------------

                              Comment

                              Về tác giả

                              Collapse

                              sidesignvn Kỹ sư Điện - Tự động hóa. Tốt nghiệp Bách Khoa Hà nội năm 2000. Tìm hiểu thêm về sidesignvn

                              Bài viết mới nhất

                              Collapse

                              Đang tải...
                              X