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

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

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

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

Q&A

解決済

2回答

1271閲覧

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

Alyn

総合スコア50

Arduino

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

0グッド

0クリップ

投稿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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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と同じ波形ですので気にしないでください。
guest

回答2

0

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

ちょっと追ってみると、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

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Alyn

2022/10/26 03:40

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

2022/10/27 22:35

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

0

ベストアンサー

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

シリアル通信する相手が、「一定時間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

総合スコア13528

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問