头部背景图片
ranyueの月染霜华 |
ranyueの月染霜华 |

基于海思HI3519V101—SPI应用编程驱动TMC5041

2020-06-05
配合笔记参考http://note.youdao.com/noteshare?id=4d918ff95b075f08eb49aa081287d90f
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include<stdlib.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static void pabort(const char *s)
{
      perror(s);
      abort();

}

static const char *device = "/dev/spidev1.0"; //设备名
static uint8_t mode;    //设备模式
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
//对TMC寄存器的宏定义
unsigned int GCONF = 0x00;                                    
unsigned int CHOPCONF = 0x6c;                                 
unsigned int IHOLD_IRUN = 0x30;                               
unsigned int TZEROWAIT = 0x2c;                               
unsigned int PWMCONF = 0x10;
unsigned int VHIGH = 0x32;
unsigned int VCOOLTHRS = 0x31;
unsigned int RAMPMODE = 0x20;
//速度参数寄存器
unsigned int VSTART = 0x23;
unsigned int A1 = 0x24;
unsigned int V1 = 0x25;
unsigned int AMAX = 0x26;
unsigned int VMAX = 0x27;
unsigned int DMAX = 0x28;
unsigned int D1 = 0x2A;
unsigned int VSTOP = 0x2B;

//当前速度寄存器
unsigned int VACTUAL = 0x22;
//当前位置寄存器
unsigned int XACTUAL = 0x21;
//给定位置寄存器
unsigned int XTARGET = 0x2D;
/*******************************************************************
* 名称:                sensor_write_register
* 功能:                将信息通过SPI写入外挂设备的指定寄存器的信息
* 入口参数:         fd        SPI文件描述符 
*                              addr     设备寄存器地址
*                              data   写入的数据
*出口参数:          无
*******************************************************************/  
static void sensor_write_register(int fd,unsigned int addr, unsigned int data) 
{

      int ret;
      //定义待发送的数据
      uint8_t tx[5];
      tx[0] = 0X80 | addr & 0xff;
      tx[1] = 0xff & (data >> 24) ;
      tx[2] = 0xff & (data >> 16) ;
      tx[3] = 0xff & (data >> 8) ;
      tx[4] = 0xff & (data >> 0) ;

      uint8_t rx[ARRAY_SIZE(tx)] = {0};
      struct spi_ioc_transfer tr = {

             .tx_buf = (unsigned long)tx,   //定义发送缓冲区指针
             .rx_buf = (unsigned long)rx,   //定义接收缓冲区指针
             .len = ARRAY_SIZE(tx),                    
             .delay_usecs = delay,
             .speed_hz = speed,
             .bits_per_word = bits, 
      };      
      //进行一次读写操作
      ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);//执行spidev.c中ioctl的default进行数据传输
      if (ret == 1)
             pabort("can't send spi message"); 

}
/*******************************************************************
* 名称:                sensor_read_register
* 功能:                读取外挂设备指定寄存器的数据
* 入口参数:         fd        SPI文件描述符 
*                              addr     设备寄存器地址
*                              rev   接收收到的数据
*出口参数:          返回读取的数据长度
*******************************************************************/  
int sensor_read_register(int fd,unsigned int addr,uint8_t rev[])
{

      int ret;
      //定义待发送的数据
      uint8_t tx[5];
      tx[0] = addr;     
      int t;
      int len;

      uint8_t rx[ARRAY_SIZE(tx)] = {0}; 
      struct spi_ioc_transfer tr = {

             .tx_buf = (unsigned long)tx,   //定义发送缓冲区指针
             .rx_buf = (unsigned long)rx,   //定义接收缓冲区指针
             .len = ARRAY_SIZE(tx),                    
             .delay_usecs = delay,
             .speed_hz = speed,
             .bits_per_word = bits, 
      };      
      //进行一次读写操作
      ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);//执行spidev.c中ioctl的default进行数据传输
      if (ret == 1)
             pabort("can't send spi message");
      for(ret=0; ret<ARRAY_SIZE(rx);ret++)
      {
            rev[ret] = rx[ret];
      }
      return len = ARRAY_SIZE(rx);
}
/*******************************************************************
* 名称:                Spi_Set
* 功能:                配置spi总线的参数
* 入口参数:         fd        SPI文件描述符 
*                              addr     设备寄存器地址
*                              rev   接收收到的数据
*出口参数:          正确返回大于0 错误返回小于0
*******************************************************************/  
int Spi_Set(int fd)
{
      int ret = -1;
      mode |= SPI_CPHA;//时钟相位
      mode |= SPI_CPOL;//时钟继续  
      mode &= ~SPI_CS_HIGH;  //片选高电平
      ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);  //SPI模式设置可写

      if (ret == -1)

             pabort("can't set spi mode");
      ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); //SPI模式设置可读

      if (ret == -1)
             pabort("can't get spi mode");

      ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);  //SPI的bit/word设置可写

      if (ret == -1)

             pabort("can't set bits per word");

      ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);   //SPI的bit/word设置可读

      if (ret == -1)

             pabort("can't get bits per word");

      ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);     //SPI的波特率设置可写

      if (ret == -1)

             pabort("can't set max speed hz");

      ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);   //SPI的波特率设置可读

      if (ret == -1)

             pabort("can't get max speed hz");

      printf("spi mode: %d\n", mode);

      printf("bits per word: %d\n", bits);
      printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
      return ret;
}
/*******************************************************************
* 名称:                Twe_Addr
* 功能:                计算第二通道的偏移量
* 入口参数:        addr     设备寄存器的偏移基地址
*出口参数:          返回偏移后的地址
*******************************************************************/ 
unsigned int Twe_Addr(unsigned int addr)
{
      int new_addr = addr + 0x20;
}
/*******************************************************************
* 名称:                Math_Acceleration
* 功能:                计算云台的实际加速度
* 入口参数:        Accel     
*出口参数:          无
*******************************************************************/
void Math_Acceleration(unsigned int Accel)
{
      //计算实际加速度(Acceleration_Speed = 12.4*2^-4*寄存器的值 = 0.775*10000)
      double Acceleration = 0.775*Accel;
      printf("Acceleration:%02lf\n", Acceleration);
}
/*******************************************************************
* 名称:                Tmc_Init
* 功能:                初始化TMC5041的寄存器参数
* 入口参数:         fd        SPI文件描述符    
*出口参数:          无
*******************************************************************/
void Tmc_Init(int fd)
{
      //第一组初始化
      sensor_write_register(fd,GCONF,0x00000008);  // GCONF=8: Enable Position compare pulse and INT outputs                                                      
      sensor_write_register(fd,CHOPCONF,0x000100C5);  // CHOPCONF: TOFF=5, HSTRT=4, HEND=1, TBL=2, CHM=0 (spreadCycle)                                                      
      sensor_write_register(fd,IHOLD_IRUN,0x00011F05);  // IHOLD_IRUN: IHOLD=5, IRUN=31 (max. current), IHOLDDELAY=1000(静止电流为5,检测电阻,控制掉电后的周期)                                                   
      sensor_write_register(fd,TZEROWAIT,0x00002710);  // TZEROWAIT=10000  DECE后的wait时间 (下降到零速度或反向旋转的等待时间)                                                   
      sensor_write_register(fd,PWMCONF,0x000401C8);  // PWM_CONF: AUTO=1, 1/1024 Fclk, Switch amplitude limit=200, Grad=1 
      sensor_write_register(fd,VHIGH,0x00061A80);  // VHIGH=400 000: Set VHIGH to a high value to allow stealthChop                                                      
      sensor_write_register(fd,VCOOLTHRS,0x00007530);  // VCOOLTHRS=30000: Set upper limit for stealthChop to about 30RPM 
      sensor_write_register(fd,VSTART,0X00000005);//  VSTART = 1
      sensor_write_register(fd,VSTOP,0X0000000A); // VSTOP = 10 Stop velocity (Near to zero)
      //第二组通道初始化
      sensor_write_register(fd,(CHOPCONF+0x10),0x000100C5);  // CHOPCONF: TOFF=5, HSTRT=4, HEND=1, TBL=2, CHM=0 (spreadCycle)
      sensor_write_register(fd,PWMCONF+0x08,0x000401C8);  // PWM_CONF: AUTO=1, 1/1024 Fclk, Switch amplitude limit=200, Grad=1  
      sensor_write_register(fd,Twe_Addr(IHOLD_IRUN),0x00011F05);  // IHOLD_IRUN: IHOLD=5, IRUN=31 (max. current), IHOLDDELAY=1000 
      sensor_write_register(fd,Twe_Addr(TZEROWAIT),0x00002710);  // TZEROWAIT=10000  DECE后的wait时间  
      sensor_write_register(fd,Twe_Addr(VHIGH),0x00061A80);  // VHIGH=400 000: Set VHIGH to a high value to allow stealthChop  
      sensor_write_register(fd,Twe_Addr(VCOOLTHRS),0x00007530);  // VCOOLTHRS=30000: Set upper limit for stealthChop to about 30RPM  
      sensor_write_register(fd,Twe_Addr(VSTART),0X00000005);//  VSTART = 1
      sensor_write_register(fd,Twe_Addr(VSTOP),0X0000000A); // VSTOP = 10 Stop velocity (Near to zero)                         

}
/*******************************************************************
* 名称:                Curr_Pos
* 功能:                初始化TMC5041的寄存器参数
* 入口参数:         fd        SPI文件描述符 
*                     rev          保存位置的信息   
*出口参数:          无
*******************************************************************/
void Curr_Pos(int fd,uint8_t rev[])
{
      int i =0;
      int len_rl = sensor_read_register(fd,XACTUAL,rev);

      for(i=0;i<len_rl;i++)
      {
            if(i==0)
            printf("RL\n");
            printf("%02x ",rev[i]);
      }
      int len_ud = sensor_read_register(fd,Twe_Addr(XACTUAL),rev);
      for(i=0;i<len_ud;i++)
      {
            if(i==0)
            printf("UD\n");
            printf("%02x ",rev[i]);
      }
}
/*******************************************************************
* 名称:                Motion_Left
* 功能:                给定一定速度来驱动电机左转
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Left(int fd)
{
      //将v1和vmax设为一样的 
      sensor_write_register(fd,V1,0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,VMAX,0X00003A98); // VMAX = 100 00 
      sensor_write_register(fd,A1,0X000000C8); // // A1 = 200   
      sensor_write_register(fd,AMAX,0X000000C8); // AMAX = 200
      sensor_write_register(fd,D1,0X000003E8); // D1 = 1000  
      sensor_write_register(fd,DMAX,0X000003E8); // DMAX = 1000  
      //正向旋转
      sensor_write_register(fd,RAMPMODE,0x00000001);  // RAMPMODE=1 (positive velocity) 
      Math_Acceleration(200);

      return 0;
}
/*******************************************************************
* 名称:                Motion_Right
* 功能:                给定一定速度来驱动电机右转
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Right(int fd)
{    
      //将v1和vmax设为一样的 
      sensor_write_register(fd,V1,0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,VMAX,0X00003A98); // VMAX = 100 00 
      sensor_write_register(fd,A1,0X000000C8); // // A1 = 200   
      sensor_write_register(fd,AMAX,0X000000C8); // AMAX = 200
      sensor_write_register(fd,D1,0X000003E8); // D1 = 1000  
      sensor_write_register(fd,DMAX,0X000003E8); // DMAX = 1000  
      //反向旋转
      sensor_write_register(fd,RAMPMODE,0x00000002);  // RAMPMODE=1 (negative velocity)
      //计算实际加速度(Acceleration_Speed = 12.4*2^-4*寄存器的值 = 0.775*10000)
      Math_Acceleration(200);
      return 0;
}
/*******************************************************************
* 名称:                Motion_Up
* 功能:                给定一定速度来驱动电机向上转
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Up(int fd)
{     
        //将v1和vmax设为一样的 
      sensor_write_register(fd,Twe_Addr(V1),0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,Twe_Addr(VMAX),0X00003A98); // VMAX = 100 00 
        sensor_write_register(fd,Twe_Addr(A1),0X000000C8); // // A1 = 200   
      sensor_write_register(fd,Twe_Addr(AMAX),0X000000C8); // AMAX = 200
      sensor_write_register(fd,Twe_Addr(D1),0X000003E8); // D1 = 1000  
      sensor_write_register(fd,Twe_Addr(DMAX),0X000003E8); // DMAX = 1000  
      //正向旋转
      sensor_write_register(fd,Twe_Addr(RAMPMODE),0x00000001);  // RAMPMODE=1 (negative velocity) 
      //计算实际加速度(Acceleration_Speed = 12.4*2^-4*寄存器的值 = 0.775*10000)
      Math_Acceleration(200);
      return 0;
}
/*******************************************************************
* 名称:                Motion_Down
* 功能:                给定一定速度来驱动电机向下转
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Down(int fd)
{     

      //将v1和vmax设为一样的 
      sensor_write_register(fd,Twe_Addr(V1),0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,Twe_Addr(VMAX),0X00003A98); // VMAX = 100 00 
      sensor_write_register(fd,Twe_Addr(A1),0X000000C8); // // A1 = 200   
      sensor_write_register(fd,Twe_Addr(AMAX),0X000000C8); // AMAX = 200
      sensor_write_register(fd,Twe_Addr(D1),0X000003E8); // D1 = 1000  
      sensor_write_register(fd,Twe_Addr(DMAX),0X000003E8); // DMAX = 1000  
      //反向旋转
      sensor_write_register(fd,Twe_Addr(RAMPMODE),0x00000002);  // RAMPMODE=1 (negative velocity) 
      Math_Acceleration(200);
      return 0;
}
/*******************************************************************
* 名称:                Motion_Stop_RL
* 功能:                控制左右电机停止
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Stop_RL(int fd)
{     
      sensor_write_register(fd,V1,0X00000000); // V1 = 50 000 Acceleration threshold velocity V1
      sensor_write_register(fd,VMAX,0X00000000); // VMAX = 50 000                                                
      return 0;
}
/*******************************************************************
* 名称:                Motion_Stop_UD
* 功能:                控制上下电机停止
* 入口参数:         fd        SPI文件描述符   
*出口参数:          0
*******************************************************************/
int Motion_Stop_UD(int fd)
{     
      sensor_write_register(fd,Twe_Addr(V1),0X00000000); // V1 = 50 000 Acceleration threshold velocity V1
      sensor_write_register(fd,Twe_Addr(VMAX),0X00000000); // VMAX = 50 000                                                
      return 0;
}
/*******************************************************************
* 名称:                Motion_MovPos
* 功能:                控制上下电机停止
* 入口参数:         fd        SPI文件描述符 
*                     Position_UD 给定需要指定的上下位置
*                     Position_RL 给定需要指定的左右位置
*出口参数:          0
*******************************************************************/
void Motion_MovPos(int fd, unsigned int Position_UD, unsigned int Position_RL)
{
      //设置左右方向的参数
      sensor_write_register(fd,V1,0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,VMAX,0X00003A98); // VMAX = 100 00 
      sensor_write_register(fd,A1,0X000000C8); // // A1 = 200   
      sensor_write_register(fd,AMAX,0X000000C8); // AMAX = 200
      sensor_write_register(fd,D1,0X000003E8); // D1 = 1000  
      sensor_write_register(fd,DMAX,0X000003E8); // DMAX = 1000  
      sensor_write_register(fd,RAMPMODE,0x00000000);  // RAMPMODE=1 (positive velocity) 
       //设置上下方向的参数
      sensor_write_register(fd,Twe_Addr(V1),0X00003A98); // V1 = 100 00 Acceleration threshold velocity V1
      sensor_write_register(fd,Twe_Addr(VMAX),0X00003A98); // VMAX = 100 00 
      sensor_write_register(fd,Twe_Addr(A1),0X000000C8); // // A1 = 200   
      sensor_write_register(fd,Twe_Addr(AMAX),0X000000C8); // AMAX = 200
      sensor_write_register(fd,Twe_Addr(D1),0X000003E8); // D1 = 1000  
      sensor_write_register(fd,Twe_Addr(DMAX),0X000003E8); // DMAX = 1000  
      sensor_write_register(fd,Twe_Addr(RAMPMODE),0x00000000);  // RAMPMODE=1 (negative velocity)

      //选择上下左右的位置
      sensor_write_register(fd,Twe_Addr(XTARGET),Position_UD);
      sensor_write_register(fd,Twe_Addr(XTARGET),Position_RL);  
}

int main(int argc, char *argv[])

{
      int exit=0;
      int ret = -1;
      int fd;
      uint8_t rev[50];

      fd = open(device, O_RDWR);       //打开"/dev/spidev1.0"
      if (fd < 0)
             pabort("can't open device");
      ret = Spi_Set(fd);
      if(ret < 0)
      {
            printf("spi set error\n");
      }
      Tmc_Init(fd);
        while (!exit)
        {
             int ch = getchar();
             switch(ch)
             {
             case 'h':
                  Motion_Right(fd);
                  sleep(1);
                  Motion_Left(fd);
                  sleep(1);
                  Motion_Up(fd);
                  sleep(1);
                  Motion_Down(fd);
                  sleep(1);
                  //回到指定位置
                  Motion_MovPos(fd,0Xfffff155,0X00000000);
                  break;
             case 's':
                  printf("----------Motion_Stop_RL--------\n");
                  Motion_Stop_RL(fd);
                  break;
             case 'a':
                  printf("----------Motion_Stop_UD--------\n");
                  Motion_Stop_UD(fd);
                  break;
             case 'r':
                  printf("---------Motion_Right-----------\n");
                  Motion_Right(fd);
                  break;
             case 'l':
                  printf("---------Motion_Left------------\n");
                  Motion_Left(fd);
                  break;
             case 'u':
                  printf("----------Motion_Up-------------\n");
                  Motion_Up(fd);
                  break;
             case 'd':
                  printf("----------Motion_Down-----------\n");
                  Motion_Down(fd);
                  break;
             case 'p':
                  Curr_Pos(fd,rev);
             default:
                  break;
             }
        }      


      close(fd);
      return ret;

}

基于海思HI3519V101-串口应用编程

2020-06-05
//串口相关的头文件  
#include<stdio.h>      /*标准输入输出定义*/  
#include<stdlib.h>     /*标准函数库定义*/  
#include<unistd.h>     /*Unix 标准函数定义*/  
#include<sys/types.h>   
#include<sys/stat.h>     
#include<fcntl.h>      /*文件控制定义*/  
#include<termios.h>    /*PPSIX 终端控制定义*/  
#include<errno.h>      /*错误号定义*/  
#include<string.h>  
#include<math.h>
#include<stdlib.h>
#include <fcntl.h>

//宏定义  
#define FALSE  -1  
#define TRUE   0  
#define DEV_NAME  "/dev/ttyAMA4"

/*******************************************************************
* 名称:                UART_Set
* 功能:                设置串口数据位,停止位和效验位
* 入口参数:        fd        串口文件描述符
*                              speed     串口速度
*                              flow_ctrl   数据流控制
*                           databits   数据位   取值为 7 或者8
*                           stopbits   停止位   取值为 1 或者2
*                           parity     效验类型 取值为N,E,O,,S
*出口参数:          正确返回为1,错误返回为0
*******************************************************************/  
int UART_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)  
{  

    int   i;  
    int   status;  
    int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};  
    int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};  

    struct termios options;  

    /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.
    */  
    if( tcgetattr( fd,&options)  !=  0)  
    {  
        perror("SetupSerial 1");      
        return(FALSE);   
    }  

    //设置串口输入波特率和输出波特率  
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)  
    {  
        if  (speed == name_arr[i])  
        {               
            cfsetispeed(&options, speed_arr[i]);   
            cfsetospeed(&options, speed_arr[i]);    
        }  
    }       

    //修改控制模式,保证程序不会占用串口  
    options.c_cflag |= CLOCAL;  
    //修改控制模式,使得能够从串口中读取输入数据  
    options.c_cflag |= CREAD;  

    //设置数据流控制  
    switch(flow_ctrl)  
    {  

        case 0 ://不使用流控制  
              options.c_cflag &= ~CRTSCTS;  
              break;     

        case 1 ://使用硬件流控制  
              options.c_cflag |= CRTSCTS;  
              break;  
        case 2 ://使用软件流控制  
              options.c_cflag |= IXON | IXOFF | IXANY;  
              break;  
    }  
    //设置数据位  
    //屏蔽其他标志位  
    options.c_cflag &= ~CSIZE;  
    switch (databits)  
    {    
        case 5    :  
                     options.c_cflag |= CS5;  
                     break;  
        case 6    :  
                     options.c_cflag |= CS6;  
                     break;  
        case 7    :      
                 options.c_cflag |= CS7;  
                 break;  
        case 8:      
                 options.c_cflag |= CS8;  
                 break;    
        default:     
                 fprintf(stderr,"Unsupported data size\n");  
                 return (FALSE);   
    }  
    //设置校验位  
    switch (parity)  
    {    
        case 'n':  
        case 'N': //无奇偶校验位。  
                 options.c_cflag &= ~PARENB;   
                 options.c_iflag &= ~INPCK;      
                 break;   
        case 'o':    
        case 'O'://设置为奇校验      
                 options.c_cflag |= (PARODD | PARENB);   
                 options.c_iflag |= INPCK;               
                 break;   
        case 'e':   
        case 'E'://设置为偶校验    
                 options.c_cflag |= PARENB;         
                 options.c_cflag &= ~PARODD;         
                 options.c_iflag |= INPCK;        
                 break;  
        case 's':  
        case 'S': //设置为空格   
                 options.c_cflag &= ~PARENB;  
                 options.c_cflag &= ~CSTOPB;  
                 break;   
        default:    
                 fprintf(stderr,"Unsupported parity\n");      
                 return (FALSE);   
    }   
    // 设置停止位   
    switch (stopbits)  
    {    
        case 1:     
                 options.c_cflag &= ~CSTOPB; break;   
        case 2:     
                 options.c_cflag |= CSTOPB; break;  
        default:     
                       fprintf(stderr,"Unsupported stop bits\n");   
                       return (FALSE);  
    }  

    //修改输出模式,原始数据输出  
    options.c_oflag &= ~OPOST;  

    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);  
    //options.c_lflag &= ~(ISIG | ICANON);  

    //设置等待时间和最小接收字符  
    options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */    
    options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */  

    //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读  
    tcflush(fd,TCIFLUSH);  

    //激活配置 (将修改后的termios数据设置到串口中)  
    if (tcsetattr(fd,TCSANOW,&options) != 0)    
    {  
        perror("com set error!\n");    
        return (FALSE);   
    }  
    return (TRUE);   
}  


/*******************************************************************
* 名称:                Printf_Buf
* 功能:                打印buff信息
* 入口参数:        hex_buf        串口中读到的buff
*                              len     buff的长度
*******************************************************************/  


void Printf_Buf(char hex_buf[] ,int len)
{
  int i;
  for (i = 0; i < len; i++)
  {
    printf("%02x\n", hex_buf[i]);
  }
}


/*******************************************************************
* 名称:                Just_Home
* 功能:                判断是否是home
* 入口参数:        hex_buf        串口中读到的buff
*                              len     buff的长度
*出口参数:          正确返回为0,错误返回为-1
*******************************************************************/  

int Just_Home(char hex_buf[],int len)
{
  int home[20] ={0x81,0x01,0x06,0x04,0xff};
  int i = 0;
  if(len < 0)
  {
    return -1;
  }
  for(i =0; i<len;i++)
  {
    if(hex_buf[i]!=home[i])
    {
      return -1;
    }
  }
  printf("Home\n");
  printf("------------------------\n");
  return 0;
}

/*******************************************************************
* 名称:                Just_Direction
* 功能:                对方向进行判断
* 入口参数:        hex_buf        串口中读到的buff
*                              len     buff的长度
*出口参数:          正确返回为0,错误返回为-1
*******************************************************************/ 
int Just_Direction(char hex_buf[], int len)
{
  char up[2]    = {0x03,0x01};
  char down[2]  = {0x03,0x02};
  char left[2]  = {0x01,0x03};
  char right[2] = {0x02,0x03};

  char up_left[2]    = {0x01,0x01};
  char up_right[2]   = {0x02,0x01};
  char down_left[2]  = {0x01,0x02};
  char down_right[2] = {0x02,0x02};

  char stop[2] = {0x03,0x03};
  char just[2] = {hex_buf[6],hex_buf[7]};
  if(len<0)
  {
    return -1;
  }
  else
  {
    if(up[0] == just[0] && up[1] == just[1])
    {
      printf("Up:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(down[0] == just[0] && down[1] == just[1])
    {
      printf("Down:Show Sixteen Pan_Speed:%02x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(right[0] == just[0] && right[1] == just[1])
    {
      printf("Right:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(left[0] == just[0] && left[1] == just[1])
    {
      printf("Left:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(up_left[0] == just[0] && up_left[1] == just[1])
    {
      printf("Up_Left:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(up_right[0] == just[0] && up_right[1] == just[1])
    {
      printf("Up_Right:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(down_left[0] == just[0] && down_left[1] == just[1])
    {
      printf("Down_Left:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(down_right[0] == just[0] && down_right[1] == just[1])
    {
      printf("Down_Right:Show Sixteen Pan_Speed:%x Tile_Speed:%x\n",hex_buf[4],hex_buf[5]);
      printf("------------------------\n");

    }
    if(stop[0] == just[0] && stop[1] == just[1])
    {
      printf("Stop\n");
      printf("------------------------\n");

    }
    return 0;
  }

}
/*******************************************************************
* 名称:                Just_Messge
* 功能:                对方向进行判断
* 入口参数:        num_buf        串口中读到的buff
*                              len     buff的长度
*出口参数:            传入空串返回-1
*           报文出错返回-2
*           正确则返回 1
*******************************************************************/  
int Just_Messge(char hex_buf[],int len)
{
  //对报文进行判断
  int i=0;
  if(len < 0)
  {
    printf("buff is error\n");
    return -1;
  }
  else
  {
    //头部和尾部都对的话则收到一组正确的报文
    if(hex_buf[0]==0x81 && hex_buf[len-1]==0xff)
    {
      printf("This is right Messge\n");
    }
    else
    {
      printf("This is mistake Messge\n");
      return -2;
    }
    //pan速度和Tile速度进行速度修正(hex_buf[4]为pan 速度 hex_buf[5]为Tile速度)
    if(len > 5)
    {
      if(hex_buf[4]<=0x01 || hex_buf[4]>=0x018)
      {
        //将pan速度修正为中间值 0x08
        printf("pan speed is mistake\n");
        hex_buf[4] = 0x08;
      }
      if(hex_buf[5]<=0x01 || hex_buf[5]>=0x014)
      {
        //将tile速度修正为中间值 0x07
        printf("Tile speed is mistake\n");
        hex_buf[4] = 0x07;
      }

    }
  }

  return 1;


}

/*******************************************************************
* 名称:                  UART0_Recv
* 功能:                接收串口数据
* 入口参数:        fd                  :文件描述符     
*                              rcv_buf     :接收串口中数据存入rcv_buf缓冲区中
*                              data_len    :一帧数据的长度
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/  
int UART0_Recv(int fd, char *rcv_buf,int data_len)  
{  
    int len,fs_sel;  
    fd_set fs_read;  

    struct timeval time;  

   //FD_ZERO(fd_set*); 用来清空fs_read集合,即让fs_read集合不再包含任何文件句柄。 
    FD_ZERO(&fs_read);  
   //添加要测试的描述字
    FD_SET(fd,&fs_read);  

    time.tv_sec = 20;  
    time.tv_usec = 0;  

    //使用select实现串口的多路通信  
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);  
    printf("fs_sel = %d\n",fs_sel);
    //然后调用select函数,拥塞等待文件描述符事件的到来;如果超过设定的时间,则不再等待,继续往下执行。  
    if(fs_sel)  
    {  
        len = read(fd,rcv_buf,data_len);  
        printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);  
        return len;  
    }  
    else  
    {  
        printf("Sorry,I am wrong!");  
        return FALSE;  
    }       
}

//串口参数
struct Uart_Set
{
  int speed;
  int flow_ctrl;
  int databits;
  int stopbits;
  int parity; 
};

int main (int argc, char *argv[])
{
  int fd;
  int len, i,ret;
  char hex_buf[50];//存放读入的数据
  struct Uart_Set Uart4; //初始化串口参数
    Uart4.speed = 9600;
    Uart4.flow_ctrl = 0;
    Uart4.databits = 8;
    Uart4.stopbits = 1;
    Uart4.parity = 'N';


  fd = open(DEV_NAME, O_RDWR | O_NOCTTY  | O_NDELAY);
    if(fd < 0) {
            perror(DEV_NAME);
            return -1;
    }
    //利用命令行做波特率设置
    if(argv[1]!=NULL)
    {
       int speed = atoi(argv[1]);
       int name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};
       unsigned int i = 0;
       int flag_speed = 0;
       for(i=0;i<sizeof(name_arr)/sizeof(int);i++)
       {
        if(speed==name_arr[i])
        {

          flag_speed = 1;
        }
       }  
       if (flag_speed)
       {
        printf("Set Speed in %d\n",speed);
        Uart4.speed = speed;
       }
       else
       {
        printf("Tranfor Speed mistake");
        goto end;
       }
    }

    //设置串口参数
    UART_Set(fd,Uart4.speed,Uart4.flow_ctrl,Uart4.databits,Uart4.stopbits,Uart4.parity);  
    printf("----------UART_TEST-------------\n");

  while(1)
  { 
    len = UART0_Recv(fd, hex_buf, sizeof(hex_buf));
      if (len < 0) {

            printf("read error \n");
            return -1;
      }
     // Printf_Buf(hex_buf,len);
      //进行报文格式的判断
      if(Just_Messge(hex_buf,len))
      {
          //判断方向和Home键
      Just_Home(hex_buf,len);
      Just_Direction(hex_buf,len);
      }
  }
end:
  close(fd);
  return(0);

}

P2045涂格子(fib)

2020-06-05

有排成一行的n个方格,用红(Red)、粉(Pink)、绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法.

一、总体思路(如果你只是需要代码,请直接看代码部分)
你应该重视思路,用C语言将之前数学课上的思路重现一下就好了!这些问题都可以归类到递归问题,因为每次涂色的时候考虑的情况大致类似,下面提供一种思考方式:为方便起见,
这个是最重要的假设:假设我已获得了求解这道问题的函数fib(),只要输入n是多少就能得到结果。

我们先不管第一格到第三格怎么涂色,我们先考虑倒数第2格,也就是第n-1格怎么涂色?

A、如果n-1个格子的颜色与1格子不同,那么第n个格子的颜色就被确定下来,只有一种。n-1个格子的涂色方案为fib(n-1)。n个格子的涂色方案为1*fib(n-1)。
B:当n-1和1的颜色相同那这时候,前n-1个方块的颜色方案为fib(n-2)(因为第n-1个颜色是确定的)。那么因为第n个格子可以涂两种颜色,所以n个格子的方案是2*fib(n-2)


上述的A、B是思考方式上的分类,说白了就是初中数学(中考最后一题)中要掌握的分类讨论思想---“要想解对题,此题的所有情况都要列出”,而不是我们C语言中,不是if就是else的互斥情况。

综上,解决涂色问题的表达式是:方法总数=solve(n-1)*1+2*solve(n-2);说到这,你也许就觉得懂了,但是你忘了,我们的这个函数是假设出来的,还没有实现呢!别着急,请看第二部分,实现过程。


#include<bits/stdc++.h>

using namespace std;

int main(){
    int n;
    long long fib[50] = { 3, 6, 6, 18 };//后面数据很大要用longlong
    for (int i = 4; i <= 49; i++)
    {
        fib[i] = fib[i - 1] +2 * fib[i - 2];
    }
    while (cin>>n)
    {
        cout << fib[n-1] << endl;
    }
    //system("pause");
    return 0;
}

Hello World

2020-06-05

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

$ hexo new "My New Post"

More info: Writing

Run server

$ hexo server

More info: Server

Generate static files

$ hexo generate

More info: Generating

Deploy to remote sites

$ hexo deploy

More info: Deployment

斐波那契变形

2020-06-05
这个是最重要的假设:假设我已获得了求解这道问题的函数fib(),只要输入n是多少就能得到从1开始到a的方案
A:蜜蜂要从1走到a的方案是fib(a)
//要知道到a的方案,就要知道a-1和a-2的方案就和爬楼梯一样
B:蜜蜂要从1走到a的方案是fib(b)
所以:蜜蜂从a走到b的方案是fib(b-a);(b>a)
#include<bits/stdc++.h>

using namespace std;

//此题类似于2041  斐波那契数列  

int main(){
    int n;
    cin >> n;

    long long f[55];        //注意!数组要用 long long 型 两个整数a和b(0<a<b<50)。
    f[1] = 1; f[2] = 2;
//从三开始方案就等于前两项的和
    for (int i = 3; i <= 55; i++)
    {
//斐波那契数列,后一项等于前两项的和
        f[i] = f[i - 1] + f[i - 2];
    }


    while (n--)
    {
        int a, b;
        cin >> a >> b;
        //首先计算出从1到a点的路线和
        //在计算出1到b点的路线和
        //那么从a到b点的路线和就是两路线的差值
        //比如1到4是3条路线
        //1到3是2条路线,那么3到4就是1条路线
        cout << f[b - a] << endl;

    }
    //system("pause");
    return 0;
}
  • « 上一页
  • 1
  • 下一页 »