找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2976|回复: 0
打印 上一主题 下一主题
收起左侧

单片机四驱车遥控避障寻线演示程序(GP41QS)

[复制链接]
跳转到指定楼层
楼主
希望大家一起学习学习
电路原理图如下:


单片机源程序如下:
  1. #include <stdio.h>
  2. #include <intrins.h>
  3. #include "STC12C5202AD.H"
  4. #include "sio.h"

  5. typedef struct PID
  6. {

  7.     int p;         //  比例常数 Proportional Const  
  8.     int i;         //  积分常数 Integral Const  
  9.     int d;         //  微分常数 Derivative Const  

  10.     int position;
  11.     int hisPosition;   
  12.     int lastPosition[3];
  13. } PID;

  14. static PID idata pid;
  15. static int GAIN;

  16. #define MIN9MS (XTAL/2L/256L*9L/1000L*9L/10L)       //9ms脉宽*90%
  17. #define MAX9MS (XTAL/2L/256L*9L/1000L*11L/10L)       //9ms脉宽*110%

  18. #define MIN45MS (XTAL/2L/256L*45L/10000L*9L/10L)       //4.5ms脉宽
  19. #define MAX45MS (XTAL/2L/256L*45L/10000L*11L/10L)

  20. #define MIN225MS (XTAL/2L/256L*225L/100000L*9L/10L)    //2.25ms脉宽
  21. #define MAX225MS (XTAL/2L/256L*225L/100000L*11L/10L)

  22. #define MIN056MS (XTAL/2L/256L*56L/100000L*6L/10L)     //0.56ms脉宽*60%,下限
  23. #define MAX056MS (XTAL/2L/256L*56L/100000L*14L/10L)

  24. #define MIN168MS (XTAL/2L/256L*168L/100000L*6L/10L)   //1.68ms脉宽*60%
  25. #define MAX168MS (XTAL/2L/256L*168L/100000L*14L/10L)

  26. sfr ISP_CUNTR = 0xE7;

  27. sbit LED1 = P3^0;
  28. sbit LED2 = P3^1;

  29. sbit AD_LED1 = P2^0;
  30. sbit AD_LED2 = P2^1;
  31. sbit AD_LED3 = P2^7;

  32. sbit IR_FRONT = P3^2;
  33. sbit IR_LEFT = P3^3;
  34. sbit IR_RIGHT = P2^6;
  35. sbit IR_BACK = P3^7;

  36. sbit IR_OUT = P3^5;

  37. sbit MOTO_IN_B1 = P2^5;
  38. sbit MOTO_IN_B2 = P2^4;

  39. sbit MOTO_IN_A1 = P2^3;
  40. sbit MOTO_IN_A2 = P2^2;

  41. static unsigned char idata ad_datas[8];  //8路光电管采样电压
  42. static unsigned char idata ad_datas_check[8];  //8路光电管采样电压校验值,轨道的白色背景的采样值

  43. bit power_stat;
  44. static unsigned char car_stat;  //小车状态:0,停止;1,前进;2,后退;3,左转;4,右转;5,寻线模式;ff,自控避障模式
  45. static unsigned int now;

  46. static unsigned char code led_mod_table[3][20] = {
  47.    {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
  48.    {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
  49.    {1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}
  50. };
  51. unsigned char idata led_mod = 0;
  52. static unsigned char idata led_tick = 0;
  53. static unsigned char idata led_ptr = 0;


  54. static bit test;

  55. static unsigned char tick = 0;
  56. static unsigned int pwm38k = 0;
  57. static unsigned char check;

  58. static unsigned char pwm_moto = 0;
  59. static unsigned char pwm_moto_left = 0;
  60. static unsigned char pwm_moto_right = 0;
  61. static bit moto_left_forward = 1;
  62. static bit moto_right_forward = 1;


  63. #define IR_SINGAL_DELAY 11    //接收管输出延迟载波数量
  64. #define TEST_PERIOD 1620      //评估周期,这个不同的接收管差别很大.
  65. #define IR_SINGAL_PERIOD 76   //持续发射红外线载波数量
  66. #define IR_VALID_THROLD 70    //判断是否前方有障碍的阀值

  67. /*
  68. #define IR_SINGAL_DELAY 1    //接收管输出延迟载波数量
  69. #define TEST_PERIOD 200      //评估周期,这个不同的接收管差别很大.
  70. #define IR_SINGAL_PERIOD 10   //持续发射红外线载波数量
  71. #define IR_VALID_THROLD 8    //判断是否前方有障碍的阀值
  72. */
  73. static unsigned char idata front_signal = 0;
  74. static unsigned char idata back_signal = 0;
  75. static unsigned char idata left_signal = 0;
  76. static unsigned char idata right_signal = 0;

  77. static bit front_obj = 0, back_obj = 0, left_obj = 0, right_obj = 0;

  78. /*
  79. * PCA中断计数,根据位置判断信号区域和定义,位置0表示初始,1代表引导码信号,2表示引导码间隔,
  80. * 3表示第一个bit的信号,4表示第一个bit的间隔,以次类推...
  81. * 更具体见对应的红外线协议.
  82. */
  83. static unsigned int idata pca_tick;
  84. static unsigned char idata pca_int_count;
  85. static unsigned char data pca_int_total;    /* 根据引导头确定总长度 */
  86. static unsigned int idata period;   /* 红外信号占或空周期计数 */
  87. static unsigned char idata data_buf[6];  /* 红外线协议数据缓冲区 */
  88. static unsigned int idata ccap1;        //PCA0上一次的的计数
  89. static unsigned char idata frame_dog;  //红外帧看门狗,限定时间未接收完成清除工作

  90. static void delay_ms(unsigned int v) {
  91.   unsigned int wait = pca_tick + v / 7 + 1;
  92.   while (wait != pca_tick) {
  93.       PCON |= 0x01;
  94.   }
  95. }

  96. static void delay_100us(unsigned char v) {
  97.     unsigned char wait = tick + v * 2; //每tick约50us
  98.     while (wait != tick) {
  99.         ;//PCON |= 0x01;
  100.     }
  101. }

  102. void pid_init(PID *pid)
  103. {
  104.     pid->position = 0;
  105.     pid->hisPosition = 0;
  106.     pid->lastPosition[0] = 0;
  107.     pid->lastPosition[1] = 0;
  108.     pid->lastPosition[2] = 0;
  109.     pid->p = 2;
  110.     pid->i = 0;
  111.     pid->d = 8;
  112. }

  113. void read_sensors(unsigned char sensors[]) {  //读光电传感器的采样值
  114.     unsigned char i;

  115.     for (i = 0; i < 8; i++) {  //LED熄灭状态测量一次电压
  116.         ADC_CONTR = 0xE0 | i; //设置AD通道, 快速AD采样.
  117.         delay_100us(5);          //延迟等待电压稳定
  118.         ADC_RES = 0;
  119.         ADC_CONTR = 0xE8 | i;;   //启动AD
  120.         while (!(ADC_CONTR & 0x10)) {

  121.         }
  122.         ADC_CONTR &= 0xE7;
  123.         sensors[i] = ADC_RES;
  124.     }

  125.     AD_LED1 = 0;
  126.     AD_LED2 = 0;
  127.     AD_LED3 = 0;

  128.     for (i = 0; i < 8; i++) {  //LED打开再测量一次电压,用于消除环境光的差异.
  129.         ADC_CONTR = 0xE0 | i; //设置AD通道, 快速AD采样.

  130.         delay_100us(5);          //延迟等待电压稳定

  131.         ADC_RES = 0;
  132.         ADC_CONTR = 0xE8 | i;;   //启动AD
  133.         while (!(ADC_CONTR & 0x10)) {

  134.         }
  135.         ADC_CONTR &= 0xE7;

  136.         if (ADC_RES > sensors[i])
  137.             sensors[i] = ADC_RES - sensors[i];
  138.         else
  139.             sensors[i] = ADC_RES;
  140.     }
  141.     AD_LED1 = 1;
  142.     AD_LED2 = 1;
  143.     AD_LED3 = 1;
  144. }

  145. static void read_sensors_check() { //从flash中读取光电传感器的校验值,结构是8byte的值+1字节的crc
  146.     unsigned char i, crc = 0;
  147.     IAP_ADDRH = 0;
  148.     IAP_CONTR = 0x80;  //允许ISP/IAP操作
  149.     IAP_CMD = 0x01;  //读flash

  150.     for (i = 0; i < 8; i++) {
  151.         IAP_ADDRL = i;
  152.         IAP_TRIG = 0x5A;
  153.         IAP_TRIG = 0xA5;  //启动IAP操作
  154.         _nop_();
  155.         ad_datas_check[i] = IAP_DATA;
  156.         crc += IAP_DATA;
  157. //com_putchar(IAP_DATA);
  158.     }
  159.     IAP_ADDRL = 8;
  160.     IAP_TRIG = 0x5A;
  161.     IAP_TRIG = 0xA5;  //启动IAP操作
  162.     _nop_();

  163.     if (crc != IAP_DATA) {  //crc验证错误,flash数据失效
  164.         for (i = 0; i < 8; i++) {
  165.             ad_datas_check[i] = 0xff;
  166.         }
  167.     }

  168.     IAP_CONTR = 0;    //禁止IAP,防止误操作
  169.     IAP_CMD = 0;
  170.     IAP_TRIG = 0;
  171.     IAP_ADDRH = 0xff;
  172.     IAP_ADDRL = 0xff;
  173. }

  174. static void write_sensors_check() { //将光电传感器的校验值写入flash,结构是8byte的值+1字节的crc
  175.     unsigned char i, crc = 0;
  176.     IAP_ADDRH = 0;
  177.     IAP_CONTR = 0x80;  //允许ISP/IAP操作
  178.     read_sensors(ad_datas_check);

  179.     IAP_ADDRL = 0;
  180.     IAP_CMD = 0x03;  //擦除flash
  181.     IAP_TRIG = 0x5A;
  182.     IAP_TRIG = 0xA5;  //启动IAP操作
  183.     _nop_();

  184.     IAP_CMD = 0x10;  //写flash

  185.     for (i = 0; i < 8; i++) {
  186.         IAP_ADDRL = i;
  187.         IAP_DATA = ad_datas_check[i];
  188. //com_putchar(IAP_DATA);
  189.         crc += ad_datas_check[i];
  190.         IAP_CMD = 0x02;  //写flash
  191.         IAP_TRIG = 0x5A;
  192.         IAP_TRIG = 0xA5;  //启动IAP操作
  193.         _nop_();
  194.     }

  195.     IAP_ADDRL = 8;
  196.     IAP_DATA = crc;
  197.     IAP_TRIG = 0x5A;
  198.     IAP_TRIG = 0xA5;  //启动IAP操作
  199.     _nop_();


  200.     IAP_CONTR = 0;    //禁止IAP,防止误操作
  201.     IAP_CMD = 0;
  202.     IAP_TRIG = 0;
  203.     IAP_ADDRH = 0xff;
  204.     IAP_ADDRL = 0xff;
  205. }

  206. void time0_isr() interrupt 1
  207. {
  208.     tick++;
  209.     pwm38k++;
  210.     if (pwm38k == 0)
  211.     {
  212.         front_signal = 0;
  213.         back_signal = 0;
  214.         left_signal = 0;
  215.         right_signal = 0;
  216.     } else if (pwm38k == TEST_PERIOD)
  217.     {
  218. //com_putchar(check);
  219.         if (front_signal >= IR_VALID_THROLD)
  220.         {
  221.             front_obj = 1;
  222.         } else
  223.             front_obj = 0;

  224.         if (back_signal >= IR_VALID_THROLD)
  225.         {
  226.             back_obj = 1;
  227.         } else
  228.             back_obj = 0;

  229.         if (left_signal >= IR_VALID_THROLD)
  230.         {
  231.             left_obj = 1;
  232.         } else
  233.             left_obj = 0;

  234.         if (right_signal >= IR_VALID_THROLD)
  235.         {
  236.             right_obj = 1;
  237.         } else
  238.             right_obj = 0;

  239.         pwm38k = 0xFFFF;
  240.         return;
  241.     }

  242.     if (pwm38k == 0)
  243.     {
  244.         IR_OUT = 1;
  245.         test = 0;
  246.     } else if (pwm38k == IR_SINGAL_PERIOD)
  247.     {
  248.         IR_OUT = 0;
  249.     }

  250. //    if (!test && !IR_FRONT)  //调试接收管的延迟
  251. //    {
  252. //        test = 1;
  253. //        com_putchar(tick);
  254. //    }

  255.     if (pwm38k >= IR_SINGAL_DELAY && pwm38k < IR_SINGAL_DELAY + IR_SINGAL_PERIOD)
  256.     {
  257.         if (!IR_FRONT)
  258.             front_signal++;
  259.         else
  260.         {
  261.             if (front_signal)
  262.                 front_signal--;
  263.         }

  264.         if (!IR_BACK)
  265.             back_signal++;
  266.         else
  267.         {
  268.             if (back_signal)
  269.                 back_signal--;
  270.         }

  271.         if (!IR_LEFT)
  272.             left_signal++;
  273.         else
  274.         {
  275.             if (left_signal)
  276.                 left_signal--;
  277.         }

  278.         if (!IR_RIGHT)
  279.             right_signal++;
  280.         else
  281.         {
  282.             if (right_signal)
  283.                 right_signal--;
  284.         }
  285.     }

  286.         if (pwm_moto == 0)
  287.         {
  288.             if (pwm_moto_left > 0)
  289.             {
  290.                 if (moto_left_forward)
  291.                     MOTO_IN_A2 = 1;
  292.                 else
  293.                     MOTO_IN_A1 = 1;
  294.             } else
  295.             {
  296.                 MOTO_IN_A1 = 0;
  297.                 MOTO_IN_A2 = 0;
  298.             }
  299.             if (pwm_moto_right > 0)
  300.             {
  301.                 if (moto_right_forward)
  302.                     MOTO_IN_B2 = 1;
  303.                 else
  304.                     MOTO_IN_B1 = 1;
  305.             } else
  306.             {
  307.                 MOTO_IN_B1 = 0;
  308.                 MOTO_IN_B2 = 0;
  309.             }
  310.         } else
  311.         {
  312.             if (pwm_moto == pwm_moto_left)
  313.             {
  314.                 MOTO_IN_A1 = 0;
  315.                 MOTO_IN_A2 = 0;
  316.             }
  317.             if (pwm_moto == pwm_moto_right)
  318.             {
  319.                 MOTO_IN_B1 = 0;
  320.                 MOTO_IN_B2 = 0;
  321.             }
  322.         }
  323.         pwm_moto++;
  324. }

  325. void time0_initialize(void)
  326. {
  327.     TMOD &= ~0x0F;      /* clear timer 0 mode bits */
  328.     TMOD |= 0x02;       /* put timer 0 into MODE 2 */
  329.     AUXR |= 0x80;       // timer0工作在1T模式
  330.         TH0 = 256 - XTAL / 2L / 38400L;  // 256 - XTAL/T1_12/f, f=输出时钟频率
  331.         TL0 = 0x0;

  332.     WAKE_CLKO = 0x01;  // T0在P3.4上输出时钟.

  333.     PT0 = 1;            /* 时钟0中断高优先级 */
  334.         TR0 = 1;            //
  335.         ET0 = 1;
  336. }

  337. static void wakeup (void) interrupt 2
  338. {

  339. }


  340. static void pca_isr (void) interrupt 6
  341. {
  342.     unsigned char i, j;

  343.     if (CCF0) {
  344.         CCF0 = 0;   //清PCA1中断标志
  345.         LED1 = IR_BACK;
  346.         if (!pca_int_count) {   //第一次收到信号
  347.             if (!IR_BACK) {
  348.                 ccap1 = pca_tick * 256 + CCAP0H;
  349.                 pca_int_count++;
  350.             }
  351.         } else {                //已经收到一些信号
  352.              period = pca_tick * 256 + CCAP0H - ccap1;
  353.              ccap1 = pca_tick * 256 + CCAP0H;
  354. //com_putchar(period / 256);
  355. //com_putchar(period % 256);

  356.             if (pca_int_count == 1) {
  357.                 if (period < MIN9MS || period > MAX9MS) {  //9ms
  358.                     pca_int_count = 0;
  359.                     frame_dog = 0;
  360.                 } else
  361.                     pca_int_count++;
  362.             } else if (pca_int_count == 2) {
  363.                 if (period > MIN225MS && period < MAX225MS) { //2.25ms
  364.                     pca_int_total = 3;
  365.                     pca_int_count++;
  366.                 } else if (period > MIN45MS && period < MAX45MS) { //4.5ms
  367.                     pca_int_total = 67;
  368.                     pca_int_count++;
  369.                 } else {
  370.                     pca_int_count = 0;
  371.                     frame_dog = 0;
  372.                 }
  373.             } else {
  374.                 if (IR_BACK) {
  375.                     if (period > MIN056MS && period < MAX056MS) {  //0.56ms
  376.                         if (pca_int_count >= pca_int_total) {  //帧接收完毕,下面进行有效性分析.
  377.                             if (pca_int_total == 67) { //完整信号,含有引导信号,设备码8bit,设备反码8bit,命令字8bit,命令字反码8bit
  378.                                 if ((data_buf[0] ^ data_buf[1] == 0xff) && (data_buf[2] ^ data_buf[3] == 0xff)) {
  379.                                     com_putchar(data_buf[0]);
  380.                                     com_putchar(data_buf[2]);
  381.                                     if (data_buf[0] == 0x40) {
  382.                                         switch (data_buf[2]) {
  383.                                         case 0x5F: //左
  384.                                             car_stat = 3;
  385.                                             break;
  386.                                         case 0x5B: //右
  387.                                             car_stat = 4;
  388.                                             break;
  389.                                         case 0x5A: //上
  390.                                             car_stat = 1;
  391.                                             break;
  392.                                         case 0x5E: //下
  393.                                             car_stat = 2;
  394.                                             break;
  395.                                         case 0x56: //菜单
  396.                                             car_stat = 0;
  397.                                             break;
  398.                                         case 0x0:  //数字0
  399.                                             car_stat = 0xff;
  400.                                             now = pca_tick;
  401.                                             break;
  402.                                         case 0x1:  //数字1
  403.                                             car_stat = 5;
  404.                                             pid_init(&pid);
  405.                                             GAIN = 150;
  406.                                             now = pca_tick;
  407.                                             break;
  408.                                         case 0x3:  //数字3
  409.                                             write_sensors_check();  //校验光电传感器
  410.                                             break;
  411.                                         case 0x1A:  //+号
  412.                                             pid.p++;
  413.                                             break;
  414.                                         case 0x1E:  //-号
  415.                                             if (pid.p)
  416.                                                 pid.p--;
  417.                                             break;
  418.                                         case 0x10:  //静音键
  419.                                             GAIN++;
  420.                                             break;
  421.                                         case 0x1C:  //屏显
  422.                                             if (GAIN)
  423.                                                 GAIN--;
  424.                                             break;
  425.                                         case 0x1B:  //^
  426.                                             pid.d++;
  427.                                             break;
  428.                                         case 0x1F:  //向下
  429.                                             if (pid.d)
  430.                                                 pid.d--;
  431.                                             break;
  432.                                         case 0x12: //POWER
  433.                                            // power_stat = ~power_stat;
  434.                                             break;
  435.                                         default:
  436.                                             break;
  437.                                         }
  438.                                     }
  439.                                 }
  440.                             } else {                   //重复信号,仅含有引导信号
  441.                             }
  442.                             pca_int_count = 0;
  443.                             frame_dog = 0;
  444.                         } else {
  445.                             pca_int_count++;
  446.                         }
  447.                     } else {
  448.                         pca_int_count = 0;
  449.                         frame_dog = 0;
  450.                     }
  451.                 } else {
  452.                     j = (pca_int_count - 3) / 2;
  453.                     i = j / 8;
  454.                     j = j % 8;

  455.                     if (period > MIN168MS && period < MAX168MS) {  //1.68ms
  456.                      //   com_putchar(0x01);
  457.                         data_buf[i] |= (0x01 << j);
  458.                         pca_int_count++;
  459.                     } else if (period > MIN056MS && period < MAX056MS) {  //0.56ms
  460.                      //   com_putchar(0x00);
  461.                         data_buf[i] &= ~(0x01 << j);
  462.                         pca_int_count++;
  463.                     } else {
  464.                         pca_int_count = 0;
  465.                         frame_dog = 0;
  466.                     }
  467.                 }
  468.             }
  469.         }
  470.     }

  471.     if (CF) {    //PCA计数溢出中断,19.6608MHZ晶体大约6.7ms溢出
  472.         CF = 0;
  473.         pca_tick++;
  474.         if (led_tick++ >= 10) {
  475.             led_tick = 0;

  476.             if (led_mod_table[led_mod][led_ptr++]) {
  477.                 LED1 = 0;
  478.                 LED2 = 0;
  479.             } else {
  480.                 if (left_obj || right_obj || front_obj || back_obj) {
  481.                     LED1 = 0;
  482.                     LED2 = 0;
  483.                 } else {
  484.                     LED1 = 1;
  485.                     LED2 = 1;
  486.                 }
  487.             }

  488.             led_ptr %= 20;
  489.         }

  490.         if (pca_int_count) {
  491.             frame_dog++;
  492.             if (frame_dog >= 15) {  //100ms后重新开始分析新的红外线数据包
  493.                 pca_int_count = 0;
  494.                 frame_dog = 0;
  495.             }
  496.         }
  497.     }
  498. }

  499. int read_black_line() {  //读黑线位置.
  500.         unsigned char i;
  501.         int grayscale_min;  //最黑的线
  502.         char line_begin, line_end;  //黑线对应的传感器的开始和结束位置.
  503.         int tmp;

  504.         read_sensors(ad_datas);
  505. /*
  506.         line_begin = -1; line_end= -1;
  507.         for (i = 0; i < 8; i++) {
  508. //com_putchar(ad_datas[i]);
  509. //com_putchar(ad_datas_check[i]);
  510.             tmp = (ad_datas[i] * 100);
  511.             tmp = tmp / ad_datas_check[i];
  512.             ad_datas[i] = tmp;
  513.             if (ad_datas[i] <= 40)  //灰度<=40%认为下面有部分黑线
  514.             {
  515.                 if (line_begin == -1)
  516.                     line_begin = i;
  517.                 else
  518.                     line_end = i;
  519.             }
  520. //com_putchar(ad_datas[i]);
  521.         }
  522.         if (line_begin == -1)
  523.             return -1;
  524.         if (line_end == -1)
  525.             return line_begin * 10;

  526.         return 10*line_begin + (line_end - line_begin) * 10 * ad_datas[line_begin] / (ad_datas[line_begin] + ad_datas[line_end]);
  527. */

  528.         line_begin = 0;
  529. //        ad_datas[0] = ad_datas[0] * 100 / ad_datas_check[0];
  530.         grayscale_min = 500;
  531.         for (i = 1; i < 8; i++) {
  532. //com_putchar(ad_datas[i]);
  533. //com_putchar(ad_datas_check[i]);
  534.             tmp = (ad_datas[i] * 100);
  535.             tmp = tmp / ad_datas_check[i];
  536.             ad_datas[i] = tmp;
  537.             if (ad_datas[i] <= grayscale_min)
  538.             {
  539.                 grayscale_min = ad_datas[i];
  540.                 line_begin = i;
  541.             }
  542. //com_putchar(ad_datas[i]);
  543.         }

  544.         if (grayscale_min < 50)  //灰度<50%认为是有效黑线
  545.         {
  546.             if (line_begin == 0)
  547.                 line_end = 1;
  548.             else if (line_begin == 7)
  549.             {
  550.                 line_begin = 6;
  551.                 line_end = 7;
  552.             } else if (ad_datas[line_begin - 1] < ad_datas[line_begin + 1])
  553.             {
  554.                 line_end = line_begin;
  555.                 line_begin = line_begin - 1;
  556.             } else
  557.                 line_end = line_begin + 1;
  558.             if (ad_datas[line_begin] == 0)
  559.                 ad_datas[line_begin] = 1;
  560.             if (ad_datas[line_end] == 0)
  561.                 ad_datas[line_end] = 1;
  562.             return 10*line_begin + (line_end - line_begin) * 10 * ad_datas[line_begin] / (ad_datas[line_begin] + ad_datas[line_end]);

  563.         } else
  564.             return -1;
  565. }

  566. void track_line(PID *pid) {  //未使用PID算法的版本,四驱车用PID算法效果差些,需要改进,三轮车用PID效果还可以.
  567.     int line_pos;

  568.     line_pos = read_black_line();
  569.     if (line_pos == -1)
  570.     {
  571.         return;
  572.     }
  573. com_putchar(line_pos);

  574.     if (line_pos > 45)
  575.     {
  576.         pwm_moto_left = 255;
  577.         pwm_moto_right = 255;

  578.         moto_left_forward = 0;
  579.         moto_right_forward = 1;
  580.     } else if (line_pos < 25) {
  581.         pwm_moto_left = 255;
  582.         pwm_moto_right = 255;

  583.         moto_left_forward = 1;
  584.         moto_right_forward = 0;
  585.     } else
  586.     {
  587.         pwm_moto_left = GAIN;
  588.         pwm_moto_right = GAIN;

  589.         moto_left_forward = 1;
  590.         moto_right_forward = 1;
  591.     }
  592. }

  593. /*
  594. void track_line(PID *pid) {  //使用PID算法的版本,三轮小车效果比较不错.
  595.     int p; //P增益
  596.     int i; //I增益
  597.     int d; //D增益
  598.     int gain; //控制量

  599.     pid->position = read_black_line();
  600.     if (pid->position == -1)
  601.     {
  602. //        pwm_moto_left = 0;
  603. //        pwm_moto_right = 0;
  604. //        pid_init(pid);
  605.         return;
  606.     }
  607. com_putchar(pid->position);

  608.     pid->position -= 30;

  609.     pid->hisPosition += pid->position;                 //记录偏差之和

  610.     pid->lastPosition[2] = pid->lastPosition[1]; //
  611.     pid->lastPosition[1] = pid->lastPosition[0]; //
  612.     pid->lastPosition[0] = pid->position;            //

  613.     p = (pid->p) * (pid->position); //计算比例分量(P)=比例系数*本次位置差
  614.     i = (pid->i) * (pid->hisPosition); //计算积分分量(I)=积分系数*偏差之和
  615.     d = (pid->d) * ((pid->position) - (pid->lastPosition[2])); //计算微分分量(D)=微分系数*(本次位置差-前3次的位置差)
  616.                                                                // 由于采样比较快,用本次位置-前3次位置才有足够大的控制
  617.     gain = p + i + d; //P分量和D分量相加,得到控制量

  618. //    if (gain > GAIN)
  619. //        gain = GAIN;
  620. //    if (gain < -GAIN)
  621. //        gain = -GAIN;



  622.     if (gain > 30)
  623.     {
  624.         pwm_moto_left = GAIN + gain;
  625.         pwm_moto_right = GAIN + gain;

  626.         moto_left_forward = 0;
  627.         moto_right_forward = 1;
  628.     } else if (gain < -30) {
  629.         pwm_moto_left = GAIN - gain;
  630.         pwm_moto_right = GAIN - gain;

  631.         moto_left_forward = 1;
  632.         moto_right_forward = 0;
  633.     } else
  634.     {
  635.         pwm_moto_left = GAIN - gain;
  636.         pwm_moto_right = GAIN -gain;

  637.         moto_left_forward = 1;
  638.         moto_right_forward = 1;
  639.     }
  640. }
  641. */
  642. void main (void)
  643. {
  644.     unsigned int i;

  645.     P2M0 = 0x3C;   //P2.2~P2.5  强推挽输出
  646.     P3M0 = 0x30;   //P3.4,P3.5强输出.

  647.     P1ASF = 0xff;   //P1.7~P1.0用做AD

  648.     i = 0;
  649.     MOTO_IN_A1 = 0;
  650.     MOTO_IN_A2 = 0;
  651.     MOTO_IN_B1 = 0;
  652.     MOTO_IN_B2 = 0;

  653.    
  654.     EA = 0;

  655.     power_stat = 0;

  656.     time0_initialize();

  657. //    com_initialize ();    /* initialize interrupt driven serial I/O */
  658. //    com_baudrate (14400); /* setup for 14400 baud */
  659. /*
  660.     CMOD = 0x01;          // #00000001B,PCA空闲计数,PCA计数源=Fosc/12,PCA溢出中断(做一个定时器使用)
  661.     CCON = 0x00;          //PCA中断标志清0,PCA停止计数
  662.     CL = 0x0;
  663.     CH = 0x0;

  664.     CCAPM1 = 0x31;        //PCA1上升下降沿捕获
  665. */

  666.     CMOD = 0x03;          // #00000011B,PCA空闲计数,PCA计数源=fosc/2,PCA溢出中断
  667.     CCON = 0x00;          //PCA中断标志清0,PCA停止计数
  668.     CL = 0x0;
  669.     CH = 0x0;

  670.     CCAPM0 = 0x31;        //PCA0上升下降沿捕获

  671. /*
  672.     CCAPM0 = 0x42;        //PCA0工作模式:8位pwm
  673.     PCA_PWM0 = 0x00;
  674.     CCAP0L = 0x40;        //25%占空比,可调节占空比来调节发射功率.低电平驱动.
  675.     CCAP0H = 0x40;
  676. */


  677. //    EPCA_LVD = 1;         //允许PCA和低压检测中断  
  678.     ELVD = 1;

  679.     car_stat = 0x00;
  680.     pca_tick = 0;
  681.     pca_int_count = 0;
  682.     frame_dog = 0;


  683.     EA = 1;                         /* Enable Interrupts */
  684.     CR = 1;                         //启动PCA计数

  685.     now = pca_tick;

  686.     delay_ms(200);

  687.     read_sensors_check();

  688.     while (1)
  689.     {
  690.         if (power_stat) {
  691.          //   auto_power_down();  //自动关机
  692.         }
  693.         switch (car_stat) {
  694.         case 0:
  695. /*
  696.             MOTO_IN_A1 = 0;
  697.             MOTO_IN_A2 = 0;
  698.             MOTO_IN_B1 = 0;
  699.             MOTO_IN_B2 = 0;
  700. */
  701.             pwm_moto_left = 0;
  702.             pwm_moto_right = 0;
  703.             break;
  704.         case 1:
  705.             if (!front_obj) {
  706. /*
  707.                 MOTO_IN_A1 = 0;
  708.                 MOTO_IN_A2 = 1;
  709.                 MOTO_IN_B1 = 0;
  710.                 MOTO_IN_B2 = 1;
  711. */
  712.                 moto_left_forward = 1;
  713.                 moto_right_forward = 1;
  714.                 pwm_moto_left = 255;
  715.                 pwm_moto_right = 255;
  716.             } else {
  717. /*
  718.                 MOTO_IN_A1 = 1;
  719.                 MOTO_IN_A2 = 0;
  720.                 MOTO_IN_B1 = 1;
  721.                 MOTO_IN_B2 = 0;

  722.                 delay(1000);
  723. */
  724.                 car_stat = 0;
  725.             }
  726.             break;
  727.         case 2:
  728.             if (!back_obj) {
  729.                 moto_left_forward = 0;
  730.                 moto_right_forward = 0;

  731.                 pwm_moto_left = 255;
  732.                 pwm_moto_right = 255;
  733. /*
  734.                 MOTO_IN_A1 = 1;
  735.                 MOTO_IN_A2 = 0;
  736.                 MOTO_IN_B1 = 1;
  737.                 MOTO_IN_B2 = 0;
  738. */
  739.             } else {
  740. /*
  741.                 MOTO_IN_A1 = 0;
  742.                 MOTO_IN_A2 = 1;
  743.                 MOTO_IN_B1 = 0;
  744. ……………………

  745. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

全部资料51hei下载地址:
四驱车遥控避障寻线演示程序(GP41QS).zip (291.78 KB, 下载次数: 7)


评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表