[Linux ドライバー] Mx1508 は 100ask_imx6ull 用ステッピング モーター 28BYJ-48 を駆動します

【ゼロ】ハードウェア関連の知識
(1) Mx1508 デュアルチャンネルブラシ付き DC モーター駆動回路
Mx1508の機能図
機能ブロック図を見ると、OUTA1 と OUTB1 が H ブリッジを構成し、OUTA2 と OUTB2 が H ブリッジを構成していることがわかります。その VCC と VDD は分離されており、2 つのチャネルの VCC と VDD は異なっていてもよいことに注意してください。VCC はロジック回路のレベルを制御すると同時に、入力端子のロジックレベルも制御します。VDD は、H ブリッジの上端の駆動電圧を制御します。したがって、VDD を VCC よりも高い電圧に接続することで、VCC よりも高い電圧でモーターを駆動することは可能ですが、それほど高い電圧ではありません。

Mx1508 駆動 DC モーターの代表的なアプリケーション図
上図によると、その典型的なアプリケーションは 2 つのチャネルを持つ DC モーターをそれぞれ駆動することであり、そのパラメータは次のとおりです: パラメータによると、重要な情報は、チャネル
Mx1508パラメータ
1 のピーク電流がチャネル 2 のピーク電流よりも大きいということです。最大駆動電圧 10V のモーターで、ピーク電流から計算すると、チャンネル 1 の長期最大電流は 2A、チャンネル 2 は 1A に達すると控えめに見積もられます。
MX1508真理値表
これは Mx1508 の論理真理値表です。つまり、入力がすべて High の場合、出力はすべて Low になります。入力が異なる場合、出力は入力値を同期します。入力がすべて Low の場合、出力はすべてハイ インピーダンス状態 (NC とみなすことができます) になります。これが重要なポイントであり、後で考慮する必要があります。
(2) 28BYJ-48 ステッピングモーター
28BYJ-48 プレビュー
28BYJ-48 についてはインターネット上で多く紹介されていますが、ここでは命名ルールの説明は省略し、主に私が理解した内容を抜粋します。 オレンジ色の線が D 相であるとしているブログもあれば、ブログではオレンジ色の線がA相と書いてあります。回路図ではオレンジ色の線とシルクスクリーンAのLEDライトが接続されているので、オレンジ色の線がA相だと考えられます。
以下に、A-AB-B-BC-C-CD-D-DA の通電順序を例に、4 相 8 ショットの各相の通電状態を簡単に紹介します。注意が必要な点:
4相8ビートの各相の通電
1
. 赤い線は COM で、VCC または GND です。これはすべての相の共通極です。VCC に接続されている場合は共通の陽極であり、GND に接続されている場合は、は共通の根拠です。
2. 上表の1/0は、赤色(COM)ラインの接続と駆動回路が異なるため、単にオレンジ線のレベルが高いか低いかを示すのではなく、導通または非導通を意味します。が異なる場合、オレンジ色の線の高レベルがフェーズ A がオンであることを意味すると単純に考えることはできません。
3. A-AB-B-BC-C-CD-D-DA の通電順序になりますが、駆動端子に向かって端子が反時計回りに回転しますので、ここではこの順序を逆と定義します。対照的に、A-AD-D-DC-C-CB-B-BA の通電順序は正回転です。
4. 通電順序は絶対的なものではなく、A相から通電を開始してもB相から通電を開始しても構いませんが、4相8ショットである限り、D相を使用するなどの「相分離」通電方法に従う必要があります。開始: D-DA-A-AB-B-BC-C-CD
5. 4相すべてをONにするとローターは四方を挟まれて急停止し、回転できなくなりますが、この時モーターが激しく発熱しますのでご注意ください。ブレーキ用途で使用される場合は、4相を短時間だけ通電し、その後4相を非通電にしてください。
上記の点はすべて、この内部構造と組み合わされています。
内部構造
初心者の場合、最も混乱するのは、ほとんどの人が赤が VCC であると言うことであり、構造図の共通レベルのいくつかは VCC に接続されており、いくつかは VCC に接続されていることです。 GNDに接続すると、めまいが起こりやすくなります。いろいろ調べてみると、赤い線がコモンポールで、VCCに接続すればアノードコモン、GNDに接続すればカソードコモン、それだけだと思います。共通アノードの場合、各相は各相のより高い駆動電流でのみ駆動できます。カソードコモンの場合は各相に高電圧を印加するだけで済みます。
(3) 100ask_imx6ull ステッピング モーター ドライブ モジュール
100askドライブモジュールの回路図
モーターは J1 CON5 に接続され、モジュールは J4 CON8 を介して汎用モジュールに接続されます。汎用モジュールの回路図によれば、駆動ピンは GPIO0 ~
GPIO3 のみに使用されます。 GPIO4は使用しない(リモコン用) 可能) GPIO0~GPI03は4つの入力端にそれぞれ接続され、出力端はモーターの各相の配線に接続され、5.1の回路もありますK 抵抗と LED ライトは出力端でグランドに接続されています
簡単な分析の後、次の結論が得られます。
1.28BYJ-48 モーターの赤いワイヤは +5V に接続されているため、各相の接続方法は共通陽極です。2. アノード共通の駆動方式を組み合わせると、比較的大きな駆動電流で各相をオンさせることができ、OUT 端子が Low のとき、電流が 5V から OUT 端子を通って GND に還流することが
わかります。
OUT端子に接続されているため、大きな駆動電流が流れますが、この時位相はONになりますが、5.1Kの抵抗によりバイパスがショートしてしまい消灯します。したがって、消灯はフェーズが機能していることを示します。
OUT 端子が High のとき、OUT 端子と共通アノード端子の電圧は両方とも 5V ですが、このときグランドに対して電圧は 5V のままです (これは、2 つの VCC を並列接続したのと同じです)今回)、電流は5.1Kの抵抗とLEDランプを通ってグランドに流れ、LEDが点灯します。また、OUT 端子と共通のアノード端子の間に電圧差がないため、駆動電流が微弱または存在せず、相は導通されません。
OUT 端子がハイインピーダンス状態の場合、OUT 端子は NC(未接続)とみなすことができます。このとき、電流は 5.1K の抵抗に直接流れ、LED ランプはグランドに流れ、LED は点灯します。ランプが点灯します。ただし、5.1K の抵抗と LED ライトのせいで電流が非常に小さく、この相を駆動する条件を満たしていないため、この相はオンになりません。

3. 上記 2 点の分析を組み合わせると、現象は次のように要約できます。光がオフの場合、位相は導通しています。光がオンの場合、位相は導通していません。同時に、制御ロジックを要約すると、OUT が L のときにフェーズがオンになります。OUT が H/Z の場合、この相は導通していません。
簡略回路図
上記の 3 点に基づいて、GPIO0 ~ GPIO3 のハイレベルとローレベルを Bit0 ~ Bit3 (低位から高位) に設定して 16 進数値を形成し、4 相 8 ビートの通電シーケンスと真理値表を組み合わせて、 get Output:
[GPIO3 GPIO2 GPIO1 GPIO0] → [0 0 1 0] → 0x02
ここで、HighからLowがD相-A相であることに注意してください。
このうち、1 は IN 端子がハイレベルであることを意味し、0 は IN 端子がローレベルであることを意味します。HはOUT端子がハイレベルであることを示し、ZはOUT端子がハイインピーダンス状態であることを示します。
4相8ビートに対応した制御値
説明する必要があるいくつかの点を次に示します。
1. Mx1508 は本質的に 2 つの H ブリッジであるため、同じチャネルの 2 つの出力が同時に H になることは存在しません。一般的なDCモータは、電流の流れる方向を制御することでモータの回転方向を制御し、実効電圧の大きさを制御することでモータの回転速度を制御し、実効電圧の大きさを制御することでモータの負荷容量を制御します。現在の。したがって、PWM モードを使用することが一般的ですが、詳細についてはテクニカルマニュアルの PWM モード A/B の説明を参照してください。
2. プログラムがピンを効果的に制御できるかどうかを確認したい場合は、共通陽極モーターによる照明の順序への影響を避けるために、最初にモーターではなくモジュールのみを接続できます。モーターを取り外した後、モジュール上の各相のライトは OUT ピンのレベルによってのみ制御されます。モーターの接続の有無は点灯現象に大きな影響を与えます。たとえば、最初のショットでは、A 相がオンになっている場合: モーターが接続されていない場合、モジュールの AD ライトはオフ、オン、オフになります。モーターが接続されている場合、AD ライトはオフになります。 , on, on, on 具体的な回路解析については、上記の結論 2 を参照してください
[1] デバイス ツリー
デバイスツリーピン
一般モジュールのシルクスクリーンは GPIO0 ~ GPIO3 ですが、実際には GPIO4_19 ~ GPIO4_22 であり、
デバイスツリー
特別なことはありません。これは ACTIVE_HIGH であることに注意してください。つまりアクティブハイです。
[2]ドライバー

#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <media/rc-core.h>
#include <linux/platform_data/media/gpio-ir-recv.h>

#define motor_NAME    "mymotor"

struct motor_msg{
    
    
  int cmd;
  int angle;
  int speed;
};
struct gpio_motor{
    
    
	int gpio;
	struct gpio_desc *gpiod;
	int flag;
};

struct motor_device{
    
    
  /*file*/
  int major;
  dev_t devid;
  struct cdev cdev;
  struct class *class;
  struct device *device;
  /*motor dev*/
  int gpio_count;
  int m_speed;
  /*motor task*/
  struct mutex lock;
};

static struct motor_msg motor_msg;
static struct motor_device motor_dev;
static struct gpio_motor *gpio_motor;

u8 Motor_Stop_cmd = 0x00;
u8 Motor_Run_cmd[8] = {
    
    0x02,0x06,0x04,0x0c,0x08,0x09,0x01,0x03};//顺时针
u8 Motor_Reverse_cmd[8] = {
    
    0x02,0x03,0x01,0x09,0x08,0x0c,0x04,0x06};//逆时针

void Set_Motor_Contorl(u8 cmd)
{
    
    
  int i = 0;
  u8 cmd_bit[4];
  unsigned long flags;
  memset(cmd_bit,0,sizeof(cmd_bit));
  for(i = 0;i<4;i++)
  {
    
    
    cmd_bit[i] = ((cmd&0x0f)>>i)&0x01;//bit0~bit3
  }
  mutex_lock(&motor_dev.lock);
  local_irq_save(flags);
  for(i = 0;i<4;i++)
  {
    
    
    gpio_set_value(gpio_motor[i].gpio,cmd_bit[i]);
    //printk("gpio[%d] cmd_bit[%d]:%d\n",gpio_motor[i].gpio,i,cmd_bit[i]);
  }
  mdelay(motor_dev.m_speed);  
  local_irq_restore(flags);
  mutex_unlock(&motor_dev.lock);
}

void Motor_Stop(void)
{
    
    
  Set_Motor_Contorl(Motor_Stop_cmd);
}

void Motor_Start(int angle)
{
    
    
  int i = 0;
  for(i = 0;i<angle;i++)
  {
    
    
    Set_Motor_Contorl(Motor_Run_cmd[0]);
    Set_Motor_Contorl(Motor_Run_cmd[1]);
    Set_Motor_Contorl(Motor_Run_cmd[2]);
    Set_Motor_Contorl(Motor_Run_cmd[3]);
    Set_Motor_Contorl(Motor_Run_cmd[4]);
    Set_Motor_Contorl(Motor_Run_cmd[5]);
    Set_Motor_Contorl(Motor_Run_cmd[6]);
    Set_Motor_Contorl(Motor_Run_cmd[7]);
  }
}

void Motor_Reverse(int angle)
{
    
    
  int i = 0;
  for(i = 0;i<angle;i++)
  {
    
    
    Set_Motor_Contorl(Motor_Reverse_cmd[0]);
    Set_Motor_Contorl(Motor_Reverse_cmd[1]);
    Set_Motor_Contorl(Motor_Reverse_cmd[2]);
    Set_Motor_Contorl(Motor_Reverse_cmd[3]);
    Set_Motor_Contorl(Motor_Reverse_cmd[4]);
    Set_Motor_Contorl(Motor_Reverse_cmd[5]);
    Set_Motor_Contorl(Motor_Reverse_cmd[6]);
    Set_Motor_Contorl(Motor_Reverse_cmd[7]);
  }
}

static ssize_t motor_drv_read(struct file *file,char __user *buf,size_t size,loff_t *offset)
{
    
    
    printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
    return 0;
}

static ssize_t motor_drv_write(struct file *file,const char __user *buf,size_t size,loff_t *offset)
{
    
    
    int err;
    int data[3];
    printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
    err = copy_from_user(data,buf,sizeof(data));
    //printk("data0:%d data1:%d data2:%d\n",data[0],data[1],data[2]);
    if(err == 0)
    {
    
    
      motor_msg.cmd = data[0];
      motor_msg.angle = data[1];
      motor_msg.speed = data[2];
      if(motor_msg.speed > 10)
         motor_msg.speed = 10;
      if(motor_msg.speed<1)
         motor_msg.speed = 1;
      motor_dev.m_speed = 1*motor_msg.speed; 
        switch(motor_msg.cmd)
      {
    
    
        case 0:
        Motor_Stop();
        break;
        case 1:
        Motor_Start(motor_msg.angle);
        break;
        case 2:
        Motor_Reverse(motor_msg.angle);
        break;
        case 3:
        Motor_Start(motor_msg.angle);
        Motor_Reverse(motor_msg.angle);
        break;
        case 4:
        Set_Motor_Contorl(0x01);
        mdelay(1000);
        Set_Motor_Contorl(0x02);
        mdelay(1000);
        Set_Motor_Contorl(0x04);
        mdelay(1000); 
        Set_Motor_Contorl(0x08);
        mdelay(1000);
        default:
        motor_msg.cmd = -1;
        break;
      }
    }else
    {
    
    
      motor_msg.cmd = -1;
    }
    return motor_msg.cmd;
}

static int motor_drv_open(struct inode *node,struct file *file)
{
    
    
    int ret = 0;
    int i = 0;
    printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
    mutex_init(&motor_dev.lock);
    for(i = 0;i<motor_dev.gpio_count;i++)
    {
    
    
      ret = gpio_request(gpio_motor[i].gpio,NULL);
      if(ret < 0)
      {
    
    
        printk("gpio %d request fail!\n",i);
      }
      ret = gpio_direction_output(gpio_motor[i].gpio,0);
      if(ret < 0)
      {
    
    
        printk("gpio %d set direction fail!\n",i);
      }
    }
    return 0;
}

static int motor_drv_close(struct inode *node,struct file *file)
{
    
    
  int i = 0;
  printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
  Motor_Stop();
  for(i = 0;i<motor_dev.gpio_count;i++)
  {
    
    
    gpio_free(gpio_motor[i].gpio);
  }
  mutex_destroy(&motor_dev.lock);
  return 0;
}

static struct file_operations motor_drv = {
    
    
  .owner =  THIS_MODULE,
  .open  =  motor_drv_open,
  .read  =  motor_drv_read,
  .write =  motor_drv_write,
  .release = motor_drv_close,
};

static int motor_probe(struct platform_device *pdev)
{
    
    
  int ret = 0;
  int i = 0;
  struct device_node *np = pdev->dev.of_node;
	enum of_gpio_flags flag;
  printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
  motor_dev.m_speed = 1;
  motor_dev.gpio_count = of_gpio_count(np);
  if(motor_dev.gpio_count)
  {
    
    
    printk("motor device gpio count = %d\n",motor_dev.gpio_count);
  }else
  {
    
    
    printk("motor device has no gpio!\n");
    return -1;
  }
  
  gpio_motor = kzalloc(sizeof(struct gpio_motor)*motor_dev.gpio_count,GFP_KERNEL);
  if (!gpio_motor)
		return -1;
  for(i = 0;i<motor_dev.gpio_count;i++)
  {
    
    
    gpio_motor[i].gpio = of_get_gpio_flags(np,i,&flag);
    if(gpio_motor[i].gpio<0)
    {
    
    
      printk("of_get_gpio_flags fail!\n");
      goto MEMERROR;
    }else
    {
    
    
      printk("gpio %d get\n",gpio_motor[i].gpio);
    }
    gpio_motor[i].gpiod = gpio_to_desc(gpio_motor[i].gpio);
    gpio_motor[i].flag = flag;
  }
   if(motor_dev.major)
  {
    
    
   motor_dev.devid = MKDEV(motor_dev.major,0);
   ret = register_chrdev_region(motor_dev.devid,1,motor_NAME);
   printk("register successful\r\n");
  }else
  {
    
    
    ret = alloc_chrdev_region(&motor_dev.devid,0,1,motor_NAME);
    motor_dev.major = MAJOR(motor_dev.devid);
    printk("alloc_chrdev successful\r\n");
  }
  if(ret<0){
    
    
    printk("%s Couldn't alloc_chrdev_region,ret = %d\r\n",motor_NAME,ret); 
    goto ERROR;
  }
  cdev_init(&motor_dev.cdev,&motor_drv);
  ret = cdev_add(&motor_dev.cdev,motor_dev.devid,1);
  if(ret<0)
  {
    
    
    printk("Cannot add cdev\n");
    goto ERROR;
  }

  motor_dev.class = class_create(THIS_MODULE,motor_NAME);
  if(IS_ERR(motor_dev.class))
  {
    
    
   printk("Cannot create class\n");
   goto ERROR;
  }else
  {
    
    
    printk("class_create successful\r\n");
  }
  
  motor_dev.device = device_create(motor_dev.class,NULL,motor_dev.devid,NULL,motor_NAME);
  if(IS_ERR(motor_dev.device))
  {
    
    
    printk("Cannot create device\n");
    goto ERROR;
  }else
  {
    
    
    printk("device_create successful\r\n");
  }
  return 0;
ERROR:
  unregister_chrdev_region(motor_dev.devid, 1);
MEMERROR:
  kfree(gpio_motor);
  return -1;
}

static int motor_remove(struct platform_device *pdev)
{
    
    
 printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
 kfree(gpio_motor);
 cdev_del(&motor_dev.cdev);
 unregister_chrdev_region(motor_dev.devid,1);
 device_destroy(motor_dev.class,motor_dev.devid);
 class_destroy(motor_dev.class);
 return 0;
}


static const struct of_device_id my_motor[]=
{
    
    
  {
    
     .compatible = "mymotor,motordrv"},
  {
    
     },
};

static struct platform_driver motor_driver = {
    
    
  .probe = motor_probe,
  .remove = motor_remove,
  .driver = {
    
    
    .name = "mymotor",
    .of_match_table = my_motor,
  },
};

static int __init motor_modules_init(void)
{
    
    
   int err;
   printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
   /* 1.register led_drv*/
   err = platform_driver_register(&motor_driver);
   return err;
}

/* 5. Exit Function */
static void __exit motor_modules_exit(void)
{
    
    
  printk("File:%s Function:%s line: %d\n",__FILE__,__FUNCTION__,__LINE__);
  platform_driver_unregister(&motor_driver);
}

/* 6. complete dev information*/

module_init(motor_modules_init);//init 
module_exit(motor_modules_exit);//exit

MODULE_LICENSE("GPL");

プログラムのロジックは、デバイスツリーから GPIO 情報を読み込む → Open 関数で GPIO を申請する → write 関数でユーザー APP からの指示を読み込んで動作する
上記は u8 パラメータを埋めることです (もちろん、上位 4 ビットは使用されません)、GPIO0 ~ GPIO3 のレベルを制御し、最終的にステッピング モーターの 1 ビート パルスを実現します。この関数にはテスト出力もあります。必要に応じてコメントを解除してください。cmd_bit[0]~cmd_bit[3]にはそれぞれ GPIO0~GPIO3 のレベルが格納されます。Motor_Start と Motor_Reverse はそれぞれ時計回りと反時計回りに回転するモーターの実行関数を表しており、実際には Set_Motor_Contorl に異なる設定値を記入することになります。ここでは作者が8ショットをより直感的に見られるように8つの設定に分けて書いていますが、めんどくさい人はサイクルとして書いても良いでしょう。
【3】アプリAPP

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>

#define ONE_CIRCLE_PULSE   512

enum COMMAND{
    
    
   Stop = 0,
   Run = 1,
   Reverse = 2,
   RunAndReverse = 3,
   Test = 4,
};

enum SPEED{
    
    
   Very_Fast = 1,
   Fast = 2,
   Medium = 3,
   Slow = 4,
   Very_Slow = 5,
};

struct motor_msg{
    
    
  int cmd;
  int angle;
  int speed;
};

static struct motor_msg motor_msg;
int fd;
int data[3];

static void MsgToData(int *data,struct motor_msg msg)
{
    
    
  data[0] = msg.cmd;
  data[1] = msg.angle;
  data[2] = msg.speed;
}

static void sig_func(int signal)
{
    
      
   int ret = 0;
   motor_msg.cmd = Stop;
   MsgToData(data,motor_msg);
   ret = write(fd,data,sizeof(data));
   close(fd);
   exit(0);
}

int main(int argc,char **argv)
{
    
    
   char *filename;
   int ret = 0;
   if(argc!=2)
   {
    
    
     printf("Usage:%s <dev>\n",argv[0]);
     return -1;
   }
   //signal(SIGSTOP,sig_func);//Ctrl+Z
   signal(SIGINT,sig_func);//Ctrl+C
   signal(SIGTERM,sig_func);
   signal(SIGKILL,sig_func);//无法捕获kill -9 ,应用层不能kill -9 退出
   filename = argv[1];
   fd = open(filename,O_RDWR);
   if(fd<0)
   {
    
    
     printf("Open file fail!\n");
     goto ERROR;
   }

   motor_msg.cmd = RunAndReverse;
   motor_msg.angle = ONE_CIRCLE_PULSE*2;
   motor_msg.speed = Very_Fast;
   MsgToData(data,motor_msg);

   ret = write(fd,data,sizeof(data));

   ERROR:
   close(fd);
   return 0;
}

アプリケーション層は配列を介してドライバーにデータを送信しますが、構造体を送信したい場合は、ここでは使用しませんでした ioctl のいくつかのメソッドを使用できます。
ここで説明する必要があるのは、次の点です。
1. sig_func と信号スロットの目的は、プログラム終了時にモーターの制御端に停止コマンドを設定することです。このプログラムは while(1) ループの実行を記述していません。メインに while(1) があり、常に 1 ステップを実行するコマンドが実行されると仮定すると、ドライバー層では次のようになります。 ループの実行は 8 ビートになります。 。しかし問題は、8拍が終わったところで完全に非導通という状況が存在しないことです。したがって、この時点でプログラムが終了した場合、ドライバー層のコードは依然として最後のビートでの GPIO の状態を維持します。このとき、ある位相が常にオンになってしまうという致命的な問題が発生する。これにより、間違いなくモーターが高温になり、異常が発生します。
2.motor_msg の Speed 項目については、論理トラップを回避するために列挙型を設定していますが、注意している人は、Very_Fast の値が Very_Slow の値より小さくなることに気づくかもしれません。これはエラーではありません ドライバーのコードを見ると、実際には Set_Motor_cmd 関数の mlay の遅延時間を Motor_msg.speed が制御していることがわかります 遅延時間が小さいと、各拍の時間間隔も小さくなりますので、モーターがより速く動作すること。テスト後の最小時間間隔は 1ms ですが、100us に設定するとモーターが正常に回転できません。1sに設定するとモーターは少し回転しにくくなります。
3. ONE_CIRCLE_PULSE の値は計算と現象を組み合わせて求められますが、28BYJ-48 モーターの説明は省略しますが、ここで注目すべきは減速比とステップ角です。8拍子で動作する場合、モーター軸の歯数は常に8なので、モーター軸のステップ角は360/(8x8) = 5.625°となり、減速比は1:64となるため、この場合、実行終了時のステップ角は 5.625°/64 となります。したがって、一周するには何発のショットが必要でしょうか? 360/(5.625/64) = 4096 ビートが必要で、プログラムでは 8 ビートがステップとして使用されるため、1 周には 4096/8 = 512 ステップが必要です。これがこの定義の価値の理由でもあり、観察すると、512 でちょうど 1 周回転できることがわかります。4相4発だとどうなるでしょうか?たとえば、AB-BC-CD-DA の場合、主軸のステップ角は 360°/(8x4) = 11.25°、したがって実行端のステップ角は 11.25°/64 となります。結局、4拍を1ステップとすると、まだ512ステップ必要であることがわかります。
4. このプログラムには実際には非常に深刻なバグがあります。つまり、アプリケーション層はデータの提供のみを担当し、残りはドライバー層に任せられています。1000 回歩くなど、非常に大きなステップを埋めると、プログラムがモーターを回転させる必要がある 一時停止するか、プログラムが途中で終了してモーターをオフにする必要がある この時点では、逐次実行のため、まだドライバー層で未完成の円の上を歩いています。したがって、総ステップ数が制限されているこの場合、一時停止することはできません。これは今回のプログラムで最も改善すべき点でもあります。1 つの方法は、while(1) を設定して、ステップを実行するたびに、合計ステップ数を記録し、一時停止コマンドを受け取った場合にループを停止することです。より簡単な方法はドライバー層にフラグを立てる方法で、フラグが1の場合はSet_motor_cmd関数を実行可能、0の場合は実行できません。しかし、すべてのアクションが書き込み関数内で実行されるため、命令側と実行側が分離されていないという問題が存在します。
関連する式
【4】メイクファイル

KERN_DIR = //home/book/100ask_imx6ull-sdk/Linux-4.9.88

all:
	make -C $(KERN_DIR) M=`pwd` modules
	$(CROSS_COMPILE)gcc -o motor_app motor_app.c


clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f motor_app


obj-m   +=motor_my_drv.o 

手順:

insmod motor_my_drv.ko
./motor_app /dev/mymotor
kill -9 [PID]
rmmod motor_my_drv.ko

参考ブログ: https:
//blog.csdn.net/anchoretor/article/details/113780470 ?ops_request_misc=&request_id=&biz_id=102&utm_term=28byj-48%E6%AD%A5%E8%BF%9B%E7%94%B5 %E6%9C%BA&utm_medium=distribute.pc_search_result.none-task-blog-2 all sobaiduweb~default-2-113780470.nonecase&spm=1018.2226.3001.4187
https://blog.csdn.net/weixin_51341083/article/d etails/
1252740 07https ://blog.csdn.net/sunshineQY/article/details/90486422?ops_request_misc=&request_id=&biz_id=102&utm_term=28byj-48%E6%AD%A5%E8%BF%9B%E7%94%B5%E6%9C %BA&utm_medium=distribute.pc_search_result.none-task-blog-2 all sobaiduweb~default-7-90486422.nonecase&spm=1018.2226.3001.4187
http://www.taichi-maker.com/homepage/reference-index/motor-reference-index/28byj-48-stepper-motor-intro/

おすすめ

転載: blog.csdn.net/qq_32006213/article/details/131371284