質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
86.12%
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

解決済

digitalWrite()とSerial1.write()の切り替えについて

Alyn
Alyn

総合スコア49

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

2回答

0グッド

0クリップ

692閲覧

投稿2022/10/25 01:20

編集2022/10/25 05:23

実現したいこと

Arduino DueでdigitalWrite()とSerial1.write()の切り替えをしたいです。
しかしdigitalWrite()からSerial1.write()を実行すると正しくシリアル通信をすることができません。
シリアルデータを送信すると1回目の送信には成功しますが、2回目以降は0が送信されてしまいます。
ちなみにArduino Megaでは切り替えをすることができていて、通信することができます。
原因と下記の理想の受信データにする方法を教えていただきたいです。
※この対象Dueの通信相手は別DueのSerial1のtx/rxで、その別DueはSerial1で受信したデータをそのまま16進数でUSBケーブルで接続したPCのシリアルモニタに送っています。

該当のソースコード

Arduino

1void setup() { 2 const byte txData[6] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; 3 4 //Serial1.write (1回目) 5 Serial1.begin(9600); 6 Serial1.write(txData, 6); 7 Serial1.end(); 8 delay(1000); 9 10 //digitalWrite 11 pinMode(18, OUTPUT); 12 digitalWrite(18, LOW); 13 delay(50); 14 digitalWrite(18, HIGH); 15 delay(100); 16 17 //Serial1.write (2回目以降) 18 for(byte i = 0; i < 5; i++) 19 { 20 Serial1.begin(9600); 21 Serial1.write(txData, 3); 22 Serial1.flush(); 23 Serial1.end(); 24 delay(1000); 25 } 26} 27 28void loop() { 29 30}

シリアルモニタ(理想の受信データ)

AA BB CC DD EE FF AA BB CC AA BB CC AA BB CC AA BB CC AA BB CC

シリアルモニタ(実際の受信データ)

AA BB CC DD EE FF 00

接続図

イメージ説明

補足情報

【Arduino Due】
https://store-usa.arduino.cc/collections/boards/products/arduino-due
https://content.arduino.cc/assets/A000056-full-pinout.pdf

【データシート】
https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf

マルチポスト

https://teratail.com/questions/h3km9w6nkmhjgm
https://qiita.com/alyn/questions/78d9963e81f53ab13f75
https://ja.stackoverflow.com/questions/91802/digitalwrite%e3%81%a8serial1-write%e3%81%ae%e5%88%87%e3%82%8a%e6%9b%bf%e3%81%88%e3%81%ab%e3%81%a4%e3%81%84%e3%81%a6

以下のような質問にはグッドを送りましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

グッドが多くついた質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

2022/10/25 01:22依頼された後にこの質問は修正されています

こちらの質問が他のユーザーから「やってほしいことだけを記載した丸投げの質問」という指摘を受けました。

Alyn

2022/10/25 02:49

質問を閉じれば回答いただけますか?
ozwk

2022/10/25 02:57

なお、質問を閉じても私は回答できない(実機がないから検証できない)ので そんなやつの言うことは聞かないというのも質問者さん次第です。
Alyn

2022/10/25 03:03

あまりにもここが過疎でしたので2つ登録して投稿しました。全部に貼り付けておきました
ozwk

2022/10/25 04:41

シリアルUSB変換ICなどを使ってPCと通信しているかと思います。 何を使っていますか? また、それはmegaのときと同じですか?
Alyn

2022/10/25 04:52

このDueの通信相手は別のDueのSerial1のtx/rxで、その別DueはSerial1で受信したデータをそのまま16進数でUSBケーブルで接続したPCのシリアルモニタに送っています。
ozwk

2022/10/25 05:07 編集

DueとDue、MegaとMegaでやっているということでしょうか。 その場合であれば、送信と受信のどちらに問題(※)があるのかわからないので Dueで送信したものをMegaで受信できませんか? ※そもそもSerialとdigitalWriteで線を共有することがあまり想定されていないので、これを問題とするのはArduinoが可哀想な気がする
Alyn

2022/10/25 05:18

図を追加しました
ozwk

2022/10/25 05:21

Megaでできたときの構成はどうなってますか?
Alyn

2022/10/25 05:25

DueとMegaをそのまま入れ替えた構成で、書き込むプログラムは同じです
ozwk

2022/10/25 05:26

2つともMegaに置き換えてますか?
Alyn

2022/10/25 05:28

はい、電圧が異なるので交換しています
ozwk

2022/10/25 05:40 編集

dueが3.3VでMegaが5VなのでdueからMegaに送る分には過電圧にはなりません。 ロジックH/Lが正しく判定できるかは微妙ですが dueのTxとMegaのRxを接続(もちろんGNDも)してどうなりますか?
Alyn

2022/10/25 05:42

前提として1回目(6bytes)のデータ送信はできていて、しかしながら2回目以降のデータ送信ができなくなっています。
ozwk

2022/10/25 05:50 編集

それはわかっています。 2回目以降の挙動が受信側がDueだから発生しているのか、送信側がDueだから発生しているのかを切り分けたいのです
Alyn

2022/10/25 05:53 編集

UARTを利用した別の通信プロトコルのトランシーバで電圧変換して送っていますが、受信側はDueとMegaどちらも同じ挙動でした。しかし送信側をMegaに変えると受信側をDueとMegaどちらでも受信できています。
ozwk

2022/10/25 05:59

根掘り葉掘り聞いて申し訳ありません 「UARTを利用した別の通信プロトコルのトランシーバ」とはなんですか?
Alyn

2022/10/25 06:08

接続図で言えばTx1-Rx1間にそれぞれそのトランシーバーを介して送受信しており、それにより異なる電圧のマイコン同士で通信可能としています。ただしビット単位で全く同じ信号を送信していますので、オシロスコープで波形を見た時にはUARTと同じ波形ですので気にしないでください。

回答2

2

解決済ということなのでさらっと。

ちょっと追ってみると、pinMode -> Serial1.beginでGPIOからUSARTにピン割当が戻っていない様子。
ピン制御のレジスタを覗いてみると、pinModeの前で0x400e0e09の値がc0だったのがpinModeの後でc8になり、Serial1.beginの後でもc0に戻っていません。0x400e0e08~はPIO Controller PIO Status Registerで、この状態を変えるには0x400e0e04~(PIO Controller PIO Disable Register)に書き込めば良い様子。なので、

digitalWrite(18, HIGH); //D18はPA11 delay(100); *(uint32_t*)0x400e0e04=0x0800;//PA11 DISABLE //Serial1.write (2回目以降)

としてみると、シリアルが復活しました。まぁ、ライブラリの不具合といえばそうですね。Arduino DueのボードライブラリのリポジトリにIssueを投げておくとArduinoコミュニティへの貢献になるかもしれません。

なお、ブレーク(TXラインL)送出は、USARTにきっとそういう機能があるはず、と調べてみたらやっぱりあったので試してみました。
Serial1が生きている(beignの後、endの前)状態で
*(uint32_t*)0x40098000=0x0200;//USART Control RegisterにBRKSTT設定
でUSART0(Serial1)のTXラインがLになり
*(uint32_t*)0x40098000=0x0400;//BRKSTP設定
でHになりました。但し、Lになる期間はバイト送信の期間で量子化されて、9600bps設定で0.5msのパルスを出すようなことはできないみたいです。

詳細はSAM3X8Eのデータシートを確認してください。

(以前、ESP32のライブラリでSerial.begin()を繰り返すとプログラムが止まるという不具合があったりして(現状修正済)beignを繰り返すのにちょっと及び腰...でも、Arduinoライブラリでボーレート変更だけの仕組みって用意されていないんですよね)

投稿2022/10/26 03:19

thkana

総合スコア7323

ozwk, Alyn👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

Alyn

2022/10/26 03:40

ありがとうございます!元々意図していた解答そのものです!データシートの読み方が分からず私はこの解答に至れませんでした。
thkana

2022/10/27 22:35

Issueも投げておきました。Arduino-SAM (Due)のボードライブラリはあまりメンテされていないようですが、なにかの機会に正式版に取り込んでもらえるかも知れません。

1

ベストアンサー

なぜそのような挙動の違いが起きるのかはわからないので質問の直接の回答になりませんが、

シリアル通信する相手が、「一定時間RxをLにする」という操作を要求するのであれば
間にマルチプレクサなどを挟んで接続先をTxとGNDとで切り替えるという方法を提案します。

イメージ説明

AND回路でも実現可能です。
TXとデジタル出力のANDを取ればデジタル出力がHの間はTXが出力に表れ、デジタル出力がLの間は出力がLになります


どうも"Serial Break"を送りたいという感じですので
これでできたりしません?

Arduino

1void setup() { 2 const byte txData[6] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; 3 4 //Serial1.write (1回目) 5 Serial1.begin(9600); 6 Serial1.write(txData, 6); 7 Serial1.flush(); 8 delay(1000); 9 10 //send serial break 11 // わざと低速で0を送る 12 Serial1.begin(300); 13 Serial1.write(0); 14 Serial1.flush(); 15 16 //Serial1.write (2回目以降) 17 Serial1.begin(9600); 18 for(byte i = 0; i < 5; i++) 19 { 20 Serial1.write(txData, 3); 21 delay(1000); 22 } 23} 24 25void loop() { 26 27} 28

投稿2022/10/25 06:12

編集2022/10/25 07:15
ozwk

総合スコア13048

gandamu👍を押しています

良いと思った回答にはグッドを送りましょう。
グッドが多くついた回答ほどページの上位に表示されるので、他の人が素晴らしい回答を見つけやすくなります。

下記のような回答は推奨されていません。

  • 間違っている回答
  • 質問の回答になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

このような回答には修正を依頼しましょう。

回答へのコメント

Alyn

2022/10/25 06:19

ありがとうございます。おっしゃるとおり『シリアル通信する相手が、「一定時間RxをLにする」という操作』を必要としています。恐らくDueの入出力レジスタか何かのレジスタにリセットのような何かが必要ではないかと考えていますが、その記述とArduinoでそれを実行可能かが分からない状況です。。
ozwk

2022/10/25 06:24

ただの興味なんですけどその相手とはなんですか? 差し支えなければ教えてください
Alyn

2022/10/25 07:42 編集

xxx通信です
Alyn

2022/10/25 07:16

breakフィールドもですが、一番はウェイクアップシグナルフレームの5msのドミナントです
ozwk

2022/10/25 07:32 編集

ウェイクアップのドミナントであれば0.25ms~5msとあるので 0を1ビットだけ送ればスタートビット含め9ビット分Lが持続します。 9600bpsならおおよそ0.9msになり要件を満たしていそうです
Alyn

2022/10/25 07:55 編集

ありがとうございます!32000-1600bpsで1byteのSerial1.write(Zero, 1);で解決できそうです。※uint8_t Zero[1] = { 0 };
ozwk

2022/10/25 07:36

Serial1.write(0, 1);はアドレス0 にあるデータを1byte送信ですので注意してくださいね
Alyn

2022/10/25 07:41

訂正しました。ありがとうございました。

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
86.12%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。