Vi Điều Khiển

Chào mừng các bạn đến với thế giới của Vi điều khiển!

--welcome to the world of microcontrollers^^ --

Điện Tử Cơ Bản

nơi khởi đầu

Lập Trình

linh hồn của phần cứng

Hiển thị các bài đăng có nhãn Thuật Toán. Hiển thị tất cả bài đăng
Hiển thị các bài đăng có nhãn Thuật Toán. Hiển thị tất cả bài đăng

Thứ Ba, 10 tháng 4, 2012

Thuật Toán Điều Khiển PID


Giới thiệu Giải thuật điều khiển PID
      PID là cách viết tắc của các từ Propotional (tỉ lệ), Integral (tích phân) và Derivative (đạo hàm). Tuy xuất hiện rất lâu nhưng đến nay PID vẫn là giải thuật điều khiển được dùng nhiều nhất trong các ứng dụng điều khiển tự động. Để giúp bạn có cái hiểu rõ hơn bản chất của giải thuật PID tôi sẽ dùng một ví dụ điều khiển vị trí của một car (xe) trên đường thẳng. Giả sử bạn có một xe (đồ chơi...) có gắn một động cơ DC. Động cơ sinh ra một lực để đẩy xe chạy tới hoặc lui trên một đường thẳng như trong hình 1. 

Hình 1. Ví dụ điều khiển vị trí xe trên đường thẳng
     Gọi F là lực do động cơ tạo ra điều khiển xe. Ban đầu xe ở vị trí A, nhiệm vụ đặt ra là điều khiển lực F (một cách tự động) để đẩy xe đến đúng vị trí O với các yêu cầu: chính xác (accurate), nhanh (fast response), ổn định (small overshot).
     Một điều rất tự nhiên, nếu vị trí hiện tại của xe rất xa vị trí mong muốn (điểm O), hay nói cách khác sai số(error) lớn, chúng ta cần tác động lực F lớn để nhanh chóng đưa xe về O. Một cách đơn giản để công thức hóa ý tưởng này là dùng quan hệ tuyến tính:
     F=Kp*e                                                                                                       (1)
     Trong đó Kp là một hằng số dương nào đó mà chúng ta gọi là hệ số P (Propotional gain), e là sai số cần điều khiển tức khoảng cách từ điểm O đến vị trí hiện tại của xe. Mục tiêu điều khiển là đưa e tiến về 0 càng nhanh càng tốt. Rõ ràng nếu Kp lớn thì F cũng sẽ lớn và xe rất nhanh chóng tiến về vị trí O. Tuy nhiên, lực F quá lớn sẽ gia tốc cho xe rất nhanh (định luật II của Newton: F=ma). Khi xe đã đến vị trí O (tức e=0), thì tuy lực F=0 (vì F=Kp*e=F=Kp*0) nhưng do quán tính xe vẫn tiếp tục tiến về bên phải và lệch điểm O về bên phải, sai số e lại trở nên khác 0, giá trị sai số lúc này được gọi là overshot (vượt quá). Lúc này, sai số e là số âm, lực F lại xuất hiện nhưng với chiều ngược lại để kéo xe về lại điểm O. Nhưng một lần nữa, do Kp lớn nên giá trị lực F cũng lớn và có thể kéo xe lệch về bên trái điểm O. Quá trình cứ tiếp diễn, xe cứ mãi dao động quanh điểm O. Có trường hơp xe dao động càng ngày xàng xa điểm O. Bộ điều khiển lúc này được nói là không ổn định. Một đề xuất nhằm giảm overshot của xe là sử dụng một thành phần “thắng” trong bộ điều khiển. Sẽ rất lý tưởng nếu khi xe đang ở xa điểm O, bộ điều khiển sinh ra lực F lớn nhưng khi xe đã tiến gần đến điểm O thì thành phần “thắng” sẽ giảm tốc độ xe lại. Chúng ta đều biết khi một vật dao động quanh 1 điểm thì vật đó có vận tốc cao nhất ở tâm dao động (điểm O). Nói một cách khác, ở gần điểm O sai số e của xe thay đổi nhanh nhất (cần phân biệt: e thay đổi nhanh nhất  không phải e lớn nhất). Mặt khác, tốc độ thay đổi của e có thể tính bằng đạo hàm của biến này theo thời gian. Như vậy, khi  xe từ A tiến về gần O, đạo hàm của sai số e tăng giá trị nhưng ngược chiều của lực F (vì e đang giảm nhanh dần). Nếu sử dụng đạo hàm làm thành phần “thắng” thì có thể giảm được overshot của xe. Thành phần “thắng” này chính là thành phần D (Derivative) trong bộ điều khiển PID mà chúng ta đang khảo sát. Thêm thành phần D này vào bộ điều khiển P hiện tại, chúng ta thu được bộ điều khiển PD nhu sau:
     F=Kp*e + Kd*(de/dt)                                                                               (2)
     Trong đó (de/dt) là vận tốc thay đổi của sai số e và Kd là một hằng số không âm gọi là hệ số D (Derivative gain).
     Sự hiện diện của thành phần D làm giảm overshot của xe, khi xe tiến gần về O, lực F gồm 2 thành phần Kp*e > =0 (P) và Kd*(de/dt) <=0 (D). Trong một số trường hợp thành phần D có giá trị lớn hơn thành phần P và lực F đổi chiều, “thắng” xe lại, vận tốc của xe vì thế giảm mạnh ở gần điểm O. Một vấn đề nảy sinh là nếu thành phần D quá lớn so với thành phần P hoặc bản thân thành phần P nhỏ thì khi xe tiến gần điểm O (chưa thật sự đến O), xe có thể dừng hẳn, thành phần D bằng 0 (vì sai số e không thay đổi nữa), lực F = Kp*e. Trong khi Kp và e lúc này đều nhỏ nên lực F cũng nhỏ và có thể không thắng được lực ma sát tĩnh. Bạn hãy tưởng tượng tình huống bạn dùng sức của mình để đẩy một xe tải nặng vài chục tấn, tuy lực đẩy tồn tại nhưng xe không thể di chuyển. Như thế, xe sẽ đứng yên mãi dù sai số e vẫn chưa bằng 0. Sai số e trong tình huống này gọi là steady state error (tạm dịch là sai số trạng thái tĩnh). Để tránh steady state error, người ta thêm vào bộ điều khiển một thành phần có chức năng “cộng dồn” sai số. Khi steady state error xảy ra, 2 thành phần P và D mất tác dụng, thành phần điều khiển mới sẽ “cộng dồn” sai số theo thời gian và làm tăng lực F theo thời gian. Đến một lúc nào đó, lực F đủ lớn để thắng ma sát tĩnh và đẩy xe tiến tiếp về điểm O. Thành phần “cộng dồn” này chính là thành phần I (Integral - tích phân) trong bộ điều khiển PID. Vì chúng ta điều biết, tích phân một đại lượng theo thời gian chính là tổng của đại lượng đó theo thời gian. Bộ điều khiển đến thời điểm này đã đầy đủ là PID:
     F=Kp*e + Kd*(de/dt)+Ki*∫edt                                                                    (3)
     (chú ý: ∫edt là tích phân của biến e theo t)
     Như vậy, chức năng của từng thành phần trong bộ điều khiển PID giờ đã rõ. Tùy vào mục đích và đối tượng điều khiển mà bộ điều khiển PID có thể được lượt bớt để trở thành bộ điều khiển P, PI hoặc PD. Công việc chính của người thiết kế bộ điều khiển PID là chọn các hệ số Kp, Kd và Ki sao cho bộ điều khiển hoạt động tốt và ổn định (quá trình này gọi là PID gain tuning). Đây không phải là việc dễ dàng vì nó phụ thuộc vào nhiều yếu tố. Tôi tóm tắt một kinh nghiệm cơ bản khi chọn các hệ số cho PID như sau:
     - Chọn Kp trước: thử bộ điều khiển P với đối tượng thật (hoặc mô phỏng), điều chỉnh Kp sao cho thời gian đáp ứng đủ nhanh, chấp nhận overshot nhỏ.
     - Thêm thành phần D để loại overshot, tăng Kd từ từ, thử nghiệm và chọn giá trị thích hợp. Steady state error có thể sẽ xuất hiện.
     - Thêm thành phần I để giảm steady state error. Nên tăng Ki từ bé đến lớn để giảm steady state error đồng thời không để cho overshot xuất hiện trở lại.
     Có một phương pháp rất phổ biến dùng để chọn các hệ số cho bộ điều khiển PID gọi là Ziegler–Nichols, bạn quan tâm có thể tự tìm hiểu thêm.
     Điều khiển PID số
     Công thức của bộ điều khiển PID trình bày trong (3) là dạng hàm liên tục của biến e, trong đó có cả thành phần tuyến tính, đạo hàm và tích phân. Tuy nhiên, hệ thống máy tính và vi điều khiển lại là hệ thống số. Muốn xây dựng bộ điều khiển PID trên máy tính hay trên vi điều khiển chúng ta phải biết cách xấp xỉ phương trình liên tục thành dạng rời rạc. Để thực hiện “số hóa” bộ điều khiển PID trước hết tôi nói sơ qua thế nào là hệ thống số (digital) so với hệ thống liên tục hay hệ thống tương tự (analog). Hãy quan sát hệ thống điều chỉnh nhiệt độ đơn giản như trong hình 2.

Hình 2. Tự động điều chỉnh nhiệt độ
      Giả sử chúng ta cần điều chỉnh nhiệt độ trong phòng ở một mức nào đó (tùy theo giá trị tham chiếu) bằng quạt. Cảm biến đo nhiệt độ và hồi tiếp về bộ khuyếch đại vi sai (so sánh và khuyếch đại). Nếu có sai số giữa giá trị tham chiếu và giá trị đo từ cảm biếm, bộ khuyếch đại vi sai sẽ tự động khuyếch đại sai số này và làm tăng hay giảm vận tốc của quạt để điều chỉnh nhiệt độ. Quá trình này xảy ra một cách liên tục. Bộ khuyếch đại vi sai trong trường hợp này chính là bộ điều khiển tương tự (analog controller). Bộ khuyếch đại này là một mạch điện tử thông thường như Opamp chẳng hạn. Nếu chúng ta thay bộ khuyếch đại này bằng một vi điều khiển thì quá trình hiệu chỉnh không còn xảy ra liên tục nữa mà theo một chu kỳ nào đó. Ví dụ cứ mỗi 10 ms chúng ta đọc giá trị từ cảm biến một lần để tính toán sai số và xuất giá trị điều khiển quạt. Bộ Vi điều khiển  thực hiện gọi là bộ điều khiển số (digital controller) và khoảng thời gian 10ms này gọi là thời gian lấy mẫu (sampling time), đó là khoảng cách giữa 2 lần điều khiển liên tiếp. Rõ ràng thời gian lấy mẫu càng nhỏ (tấn số cao) thì việc hiệu chỉnh càng tiến gần đến sự “liên tục” và chất lượng điều khiển sẽ tốt hơn. Trong các bộ điều khiển số, thời gian lấy mẫu là một yếu tố rất quan trọng. Cần tính toán để thời gian này không quá lớn nhưng cũng đừng quá nhỏ, vì như thế sẽ hao phí thời gian thực thi.
      Vì bộ điều khiển PID xây dựng trong Vi xử lý sẽ là bộ điều khiển số, chúng ta cần xấp xỉ công thức của bộ điều khiển này theo các khoảng thời gian rời rạc. Trước hết, thành phần P tương đối đơn giản vì đó là quan hệ tuyến tính Kp*e, chúng ta chỉ cần áp dụng trực tiếp công thức này mà không cần bất kỳ xấp xỉ nào. Tiếp đến là xấp xỉ cho đạo hàm của biến e. Vì thời gian lấy mẫu cho các bộ điều khiển thường rất bé nên có thể xấp xỉ đạo hàm bằng sự thay đổi của e trong 2 lần lấy mẫu liên tiếp:
      de/dt =(e(k) – e(k-1))/h.
      Trong đó e(k) là giá trị hiện tại của e, e(k-1) là giá trị của e trong lần lấy mẫu trước đó và h là khoảng thời gian lấy mẫu (h là hằng số).

Hình 3. Xấp xỉ đạo hàm của biến sai số e
     Thành phần tích phân được xấp xỉ bằng diện tích vùng giới hạn bởi hàm đường biểu diễn của e và trục thời gian. Do việc tính toán tích phân không cần quá chính xác, chúng ta có thể dùng phương pháp xấp xỉ đơn giản nhất là xấp xỉ hình chữ nhật (sai số của phương pháp này cũng lớn nhất). Ý tưởng được trình bày trong hình 4.

Hình 4. Xấp xỉ tích phân của biến sai số e
     Tích phân của biến e được tính bằng tổng diện tích các hình chữ nhật tại mỗi thời điểm đang xét. Mỗi hình chữ nhật có chiều rộng bằng thời gian lấy mẫu h và chiều cao là giá trị sai số e tại thời điểm đang xét. Tổng quát:
                                                                                    (4)
Tổng hợp các xấp xỉ, công thức của bộ điều khiển PID số được trình bày trong (5)
                                                                       (5)
Trong đó u là đại lượng output từ bộ điều khiển. Để đơn giản hóa việc tính thành phần tích phân, chúng ta nên dùng phương pháp “cộng dồn” (hay đệ quy):
                                                                                                    (6)
Với I(k) là thành phần tích phân hiện tại và I(k-1) là thành phần tích phân trước đó.
     Các công thức (5) và (6) rất dễ dàng để thực hiện bằng Vi điều khiển. Do đó, đến lúc này chúng ta đã sẵn sàng để đưa ý tưởng vào lập trình cho chip.


(nguồn: hocarv)

Chủ Nhật, 26 tháng 2, 2012

[Code C] Thuật Toán Quine MCCluskey


Thuật Toán Quine MCCluskey


Mạch logic tổ hợp là một phần công cụ để chúng ta thiết kế các mạch điện tử. Bởi thế các phương pháp rút gọn mạch logic tổ hợp là một phần quan trọng trong kiến thức môn học Điện tử số. Nó có nhiều ứng dụng lớn trong nhiều lĩnh vực của điện tử.
Phương pháp Quine MC Cluskey là phương pháp rút gọn mạch logic tổ hợp có thể tối thiểu được hàm nhiều biến và có thể tiến hành rút gọn nhờ chương trình lập trình được trên máy tính.

Các bước tối thiểu hóa: 
Gồm 4 bước cơ bản sau:
1. Lập bảng liệt kê các hạng tích dưới dạng nhị phân theo từng nhóm với số bit 1 giống nhau và xếp chúng theo số bit 1 tăng dần.
2. Gộp 2 hạng tích của mỗi cặp nhóm chỉ khác nhau 1 bit để tạo các nhóm mới. Trong mỗi nhóm mới, giữ lại các biến giống nhau, biến bỏ đi thay bằng một dấu ngang (-).
3. Lặp lại cho đến khi trong các nhóm tạo thành không cịn khả năng gộp nữa. Mỗi lần rút gọn, ta đánh dấu  #  vào các hạng ghép cặp được. Các hạng không đánh dấu trong mỗi lần rút gọn sẽ được tập hợp lại để lựa chọn biểu thức tối giản.
4. Lập bảng lựa chọn hàm.
Ta thiết lập các số hạng có thể có trong biểu thức bằng cách thay dấu gạch ngang bằng các giá trị 0 và 1 sau đó đánh dấu ký hiệu “x” dưới vị trí mà nó chứa số hạng đó.
Sau đó ta xem xét các cột chỉ chứa một dấu “x”. Các dấu “x” này đã bao quát hết tất cả các hạng tích của hàm đã cho. Do vậy, các biểu thức đó là các hạng tích đã tối giản.

Chương trình giải quyết được các bài toán phức tạp một cách nhanh chóng, kết quả được lưu trong file *.txt cùng thư mục của chương trình.

Mã nguồn:


#include<stdio.h>
#include<conio.h>
#include<math.h>
#include<string.h>
#define line printf("\n===================\n");
void doinhiphan(int x,int n,int minterm[],int nhiphan[][100]);
void nhap(int n,int minterm[]);
void sosanh(int x,int n,int nhiphan[][100],int &a,int &b);
void hienthi(int x,int nhiphan[][100],int b);
void ketqua(int x,int n,int nhiphan[][100],int a,int b,int &d);
void inraFILEhamnhap(int minterm[],int x,int n);
void inraFILErutgon(int nhiphan[][100],int b,int x);
void inraFILECACNHOM(int nhiphan[][100],int a,int b,int x,int d);
void inraFILEkq(int nhiphan[][100],int a,int b,int x,int d);

int main()
{
  int x,n;
  printf("Nhap vao so bien cua ham: ");
  scanf("%d",&x);
  printf("Nhap vao so minterm cua ham: ");
  scanf("%d",&n);
  int minterm[n],nhiphan[1000][100],a=0,b=n;//2 bien a,b danh dau lai khoang dau va cuoi mang sau 1 lan sosanh
  int d=0;//dem so thu tu cac NHOM TUY CHON co the dai dien het cac phan tu con sot lai.
 
         nhap(n,minterm);
 inraFILEhamnhap(minterm,x,n);
         doinhiphan(x,n,minterm,nhiphan);
  line;
    hienthi(x,nhiphan,b);
       sosanh(x,n,nhiphan,a,b);
  line;
    hienthi(x,nhiphan,b);
    inraFILErutgon(nhiphan,b,x);
  line;
       ketqua(x,n,nhiphan,a,b,d);
  inraFILECACNHOM(nhiphan,a,b,x,d);
  line;
   hienthi(x,nhiphan,b);
    inraFILEkq(nhiphan,a,b,x,d);
 getch(); 
}


void doinhiphan(int x,int n,int minterm[],int nhiphan[][100])
{
     for(int i=0;i<n;i++)
   for(int j=0;j<x+1;j++)
   {
          nhiphan[i][j]=0;
     }

  for(int i=0;i<n;i++)
  for(int j=0;minterm[i]>0;j++)
  {
          nhiphan[i][x-1-j]=minterm[i]%2;
          minterm[i]=minterm[i]/2;       
     }
}


void nhap(int n,int minterm[])
{
     for(int i=0;i<n;i++)
     {
          printf("Nhap minterm %d: ",i+1);
          scanf("%d",&minterm[i]);
     }
}


void hienthi(int x,int nhiphan[][100],int b)
{
     for(int i=0;i<b;i++)
  {
          for(int j=0;j<x+1;j++)
          {
                   printf("%d ",nhiphan[i][j]);
             }
             printf("\n");
          if(nhiphan[i][x]==3) printf("\n----\n");
    } 
}


void sosanh(int x,int n,int nhiphan[][100],int &a,int &b)
{
     int g,count2,kt=0,i,count2B/*khai bao o day de dung dc cho while*/;
     do
     {
          count2B=0;//chi dung trong 1 chu ky cua vong for(i),neu count2B>0 tuc la van phai rut gon tiep
          count2=0;//de dem so luot ghi lai 2minterm chi #nhau 1bit,sau do thay b=b+count2;
       for(i=a;i<b;i++)
       {
               int count4=0;//kt minterm sot hay ko
               for(int j=a;j<b;j++)
         {
              int count=0;//kiem tra 2 day minterm khac nhau 1 hay nhieu bit.      
              for(int k=0;k<x;k++)
              {
                if(nhiphan[i][k]!=nhiphan[j][k])
                {
                                    g=k;//danh dau k bang g, g chi co y nghia trong TH count==1.
                                    count++;
                               }
    
                       }
                       if(count>1) count4++;
                      
                       //truong hop # nhau 1 bit:             
                       if(count==1)//lenh if trong vong for cua 'j'.
              {    
              for(int k=0;k<x;k++)//coppy minterm da rut gon vao cuoi mang nhiphan[][].
              {
                                   if(k!=g)
                                     nhiphan[b+count2][k]=nhiphan[i][k]; 
                         else nhiphan[b+count2][g]=2;//=2 thay cho dau '-', nhiphan[j][g] ko can phai =2.
                             }
     
                              //kiem tra xem da ton tai minterm nao giong no chua:
                              for(int m=b;m<b+count2;m++)
                  {
                              int count3=0;//kt ton tai minterm giong nhau ko.
                           for(int n=0;n<x;n++)
                           {
                               if(nhiphan[m][n]==nhiphan[b+count2][n])
                               count3++;
                                      }
                            if(count3==x)
                       nhiphan[b+count2][g]=3;
                              }
                if(nhiphan[b+count2][g]!=3)//neu ko co cai nao giong thi tang cac chi so len<=>luu no.
                {
                                   count2++;
                 count2B++;
                                 nhiphan[b-1][x]=3;/*chu y trong vai TH*/   //danh dau cho~ cuoi cua 1 chu trinh ss de ham deplay chia khoang cho dep^^.
                              }
                }//ket thuc TH #1. 
        }//ket thuc for(j)
       
               //TH con sot minterm trong luot ss dau tien vi sai # >1 bit voi tat ca cac minterm con lai:        
         if(count4==b-a-1) //de dam bao: minterm nay #>2bit voi tat ca.
         {
                    for(int k=0;k<x;k++)
         {
                   nhiphan[b+count2][k]=nhiphan[i][k];//coppy minterm (#nhau 2bit tro len)nay vao cuoi mang nhiphan[][].
                    }
        count2++;
               }
    }//ket thuc for(i)
   
    if(count2!=0&&count2B>0)//dam bao luc ket thuc chu trinh (tuc count2==0&&count2B==0) thi ko can thay doi a,b
    {
            a=b;//2 bien a,b danh dau lai khoang dau va cuoi mang sau 1 lan sosanh
         b=b+count2;
       }
     }while(count2B>0);//neu sau 1 chu ky sosanh ma count2B van =0 => ket thuc.
}

void ketqua(int x,int n,int nhiphan[][100],int a,int b,int &d)
{
     int i,j,k,count;
     printf("%d_%d_%d\n",n,a,b);

     //1.reset cac minterm nhiphan[0->b][x]=0:
     for(i=0;i<b;i++)
          nhiphan[i][x]=0;

     //2.danh dau cac cot chi chua 1 dau X:
     for(i=a;i<b;i++)
     {
          for(j=0;j<n;j++)
          {
               count=0;
               for(k=0;k<x;k++)
               {
                    if(nhiphan[i][k]!=2&&nhiphan[i][k]!=nhiphan[j][k])
                    count++;
               }
               if(count==0)
               nhiphan[j][x]++;//DANH DAU = SO LAN LAP LAI PHAN TU DO
          }
     }
     //3.tu cac cot chi chua 1 dau X tim lai cac minterm tao ra dau X do:
     for(i=0;i<n;i++)
     {
          if(nhiphan[i][x]==1)
          for(j=a;j<b;j++)
          {
               count=0;
               for(k=0;k<x;k++)
               {
                    if(nhiphan[j][k]!=2&&nhiphan[i][k]!=nhiphan[j][k])
                    count++;
               }
               if(count==0)
               nhiphan[j][x]=3;//DANH DAU (=3)
          }
     }

     //4.DANH DAU CAC PHAN TU XUAT HIEN >1 LAN, NHUNG DA NAM TRONG CAC NHOM BAT BUOC:
     for(i=a;i<b;i++)
     {
          if(nhiphan[i][x]==3)
      for(j=0;j<n;j++)
      {
         count=0;
            for(k=0;k<x;k++)
            {
                 if(nhiphan[i][k]!=2&&nhiphan[i][k]!=nhiphan[j][k])
                 count++;
               }
            if(count==0)
               nhiphan[j][x]=77;//DANH DAU: THUOC NHOM BAT BUOC (=77)
          }
      }   

      //5.TU CAC PHAN TU CON SOT LAI - CHUA NAM TRONG NHOM BAT BUOC(#77), DANH DAU TAM THOI CAC NHOM CO THE DAI DIEN CHO NO(=4):
      for(i=0;i<n;i++)
      {
           if(nhiphan[i][x]!=77)
           for(j=a;j<b;j++)
           {
                count=0;
                for(k=0;k<x;k++)
                {
                     if(nhiphan[j][k]!=2&&nhiphan[i][k]!=nhiphan[j][k])
                     count++;
                }
                if(count==0)
                nhiphan[j][x]=4;//DANH DAU TAM THOI(=4), DE KT TIEP XEM CO DU DK DAI DIEN KO!
           }
      }

      //6.KIEM TRA LAI CAC NHOM VUA DANH DAU (=4) XEM CO DAI DIEN HET CHO CAC PHAN TU CON SOT LAI KO:  
      for(i=a;i<b;i++)
      {
           if(nhiphan[i][x]==4)
           {
                count=0;
                for(j=0;j<n;j++)
                {
                     if(nhiphan[j][x]!=77)
                     for(k=0;k<x;k++)
                     {
                          if(nhiphan[i][k]!=2&&nhiphan[i][k]!=nhiphan[j][k])
                          count++;
                     }
                }
                if(count==0)
                {
                  d++;
                     nhiphan[i][x]=30+d;//neu NHOM do dai dien dc het, thi danh dau (=3X) de tien sau nay in ra het cac TH KQ co the co.
                }
           }
      }

      //+++++++++++++++++++++++++++
      //7A.hien thi cac minterm vua danh dau xong(CA NHOM BAT BUOC VA TUY CHON):
      if(d==0)
      {
           count=0;
           for(i=a;i<b;i++)
           {
                if(nhiphan[i][x]==3)
                {
                     if(count==1) printf(" + ");
                     for(j=0;j<x;j++)
                     {
                          if(nhiphan[i][j]==1)
                    {
                printf("%c",65+j);
                count=1;
                          }
                       if(nhiphan[i][j]==0)
                    {
                printf("%c",97+j);
                count=1;
                          }
                     }
                }  
           }
      }
      if(d!=0)
      {
           for(int e=1;e<=d;e++)
           {
                //7B.HIEN THI CAC NHOM BAT BUOC:
                count=0;
                for(i=a;i<b;i++)
                {
                     if(nhiphan[i][x]==3)
                     {
                          if(count==1) printf(" + ");
                          for(j=0;j<x;j++)
                          {
                               if(nhiphan[i][j]==1)
                         {
                     printf("%c",65+j);
                     count=1;
                               }
                            if(nhiphan[i][j]==0)
                         {
                         printf("%c",97+j);
                     count=1;
                               }
                          }
                     }  
                }
                //7C.HIEN THI CAC NHOM TUY CHON:
                for(i=a;i<b;i++)
                {
                     if(nhiphan[i][x]==30+e)
                     {
                          printf(" + ");
                          for(j=0;j<x;j++)
                          {
                               if(nhiphan[i][j]==1)
                         {
                     printf("%c",65+j);
                     count=1;
                               }
                            if(nhiphan[i][j]==0)
                         {
                     printf("%c",97+j);
                     count=1;
                               }
                          }
                     }  
                }  
                if(e!=d) printf("\nHOAC:\n");
           }
      }
}


void inraFILEhamnhap(int minterm[],int x,int n)
{
     FILE *dtv;
     dtv=fopen("DTV.txt","a+");
          fprintf(dtv,"\n\nF(");
          for(int i=0;i<x;i++)
          {
                if(i>0) fprintf(dtv,",");
                  fprintf(dtv,"%c",65+i);
          }
          fprintf(dtv,")= {");
          for(int i=0;i<n;i++)
          {   
                if(i>0) fprintf(dtv,",");
                  fprintf(dtv,"%d",minterm[i]);
          }
          fprintf(dtv,"}\n");
     fclose(dtv);
}


void inraFILErutgon(int nhiphan[][100],int b,int x)
{
     FILE *dtv;
     dtv=fopen("DTV.txt","a+");
          for(int i=0;i<b;i++)
       {
               if(i+1<10) fprintf(dtv,"0%d  ",i+1);
               if(i+1>=10) fprintf(dtv,"%d  ",i+1);
               for(int j=0;j<x;j++)
               {
                       if(nhiphan[i][j]==2) fprintf(dtv,"-");
                       else
                    fprintf(dtv,"%d",nhiphan[i][j]);
                  }
            fprintf(dtv,"\n");
            if(nhiphan[i][x]==3) fprintf(dtv,"----\n");
          }
          //fprintf(dtv,"========================\n");
     fclose(dtv);  
}


void inraFILECACNHOM(int nhiphan[][100],int a,int b,int x,int d)
{
     FILE *dtv;
     dtv=fopen("DTV.txt","a+");
          if(d==0)
          {
               fprintf(dtv,"----\n");
               fprintf(dtv,"NHOM BAT BUOC:  ");         
         for(int i=a;i<b;i++)
            {
                    for(int j=0;j<x;j++)
                    {
                            if(nhiphan[i][x]==3)
                            if(nhiphan[i][j]==2) fprintf(dtv,"-");
                            else fprintf(dtv,"%d",nhiphan[i][j]);
                       }
                    if(nhiphan[i][x]==3&&i!=b-1) fprintf(dtv," ; ");
               }
          }
          if(d!=0)
          {
               fprintf(dtv,"----\n");
               fprintf(dtv,"NHOM BAT BUOC:  ");         
         for(int i=a;i<b;i++)
            {
                    for(int j=0;j<x;j++)
                    {
                            if(nhiphan[i][x]==3)
                            if(nhiphan[i][j]==2) fprintf(dtv,"-");
                            else fprintf(dtv,"%d",nhiphan[i][j]);
                       }
                 if(nhiphan[i][x]==3&&i!=b-1) fprintf(dtv," ; ");
               }
               fprintf(dtv,"\nNHOM TUY CHON:  ");
         for(int i=a;i<b;i++)
            {
                    for(int j=0;j<x;j++)
                    {
                            if(nhiphan[i][x]>=31)
                            if(nhiphan[i][j]==2) fprintf(dtv,"-");
                            else fprintf(dtv,"%d",nhiphan[i][j]);
                       }
                 if(nhiphan[i][x]>=31&&nhiphan[i][x]!=30+d) fprintf(dtv," ; ");
               }         
          }
          fprintf(dtv,"\n========================\n");
     fclose(dtv);
}


void inraFILEkq(int nhiphan[][100],int a,int b,int x,int d)
{
     FILE *dtv;
     dtv=fopen("DTV.txt","a+");
          //TH CHI CO CAC NHOM BAT BUOC, KO CO NHOM TUY CHON!                    
          if(d==0)
          {
               fprintf(dtv,"F(");
               for(int i=0;i<x;i++)
               {
                     if(i>0) fprintf(dtv,",");
                       fprintf(dtv,"%c",65+i);
               }
               fprintf(dtv,")= ");
               int count=0;
               for(int i=a;i<b;i++)
               {
                       if(nhiphan[i][x]==3)
                       {
                            if(count==1) fprintf(dtv," + ");
                            for(int j=0;j<x;j++)
                            {
                                    if(nhiphan[i][j]==1)
                              {
                                fprintf(dtv,"%c",65+j);
                          count=1;
                                    }
                                 if(nhiphan[i][j]==0)
                              {
                                fprintf(dtv,"%c",97+j);
                          count=1;
                                    }
                            }
                       }
               }
          }
          //TH CO CA NHOM BAT BUOC VA NHOM TUY CHON!
          if(d!=0)
          {
               for(int e=1;e<=d;e++)
               {
                       fprintf(dtv,"F(");
                       for(int i=0;i<x;i++)
                       {
                             if(i>0) fprintf(dtv,",");
                               fprintf(dtv,"%c",65+i);
                       }
                       fprintf(dtv,")= ");
                       //HIEN THI CAC NHOM BAT BUOC:
                       int count=0;
                       for(int i=a;i<b;i++)
                       {
                               if(nhiphan[i][x]==3)
                               {
                                    if(count==1) fprintf(dtv," + ");
                                    for(int j=0;j<x;j++)
                                    {
                                            if(nhiphan[i][j]==1)
                                      {
                                  fprintf(dtv,"%c",65+j);
                                  count=1;
                                            }
                                         if(nhiphan[i][j]==0)
                                      {
                                  fprintf(dtv,"%c",97+j);
                                  count=1;
                                            }
                                    }
                               }  
                       }
                       //HIEN THI CAC NHOM TUY CHON:
                       for(int i=a;i<b;i++)
                       {
                               if(nhiphan[i][x]==30+e)
                               {
                                    fprintf(dtv," + ");
                                    for(int j=0;j<x;j++)
                                    {
                                            if(nhiphan[i][j]==1)
                                      {
                                  fprintf(dtv,"%c",65+j);
                                  count=1;
                                            }
                                         if(nhiphan[i][j]==0)
                                      {
                                  fprintf(dtv,"%c",97+j);
                                  count=1;
                                            }
                                    }
                               }  
                       }
                       if(e!=d) fprintf(dtv,"\nHOAC:\n");
               }  
          }
          fprintf(dtv,"\n========================\n");
     fclose(dtv);  
}





//14s/2a/2010d tjtanja