C言語基礎を教えてください。(;_;)
17bitの整数データを送ってくるデバイスがあります。特殊(へんな仕様?)で先頭の符号bitをportで確認し、残り16bitを整数の通信で送ってきます。17bitなのでマイコンのlong型の変数に入れる必要があります。
元のソフトではportで取ったunsigned long型とshort型の論理和をしているようです。これって大丈夫でしょうか?
試しにRL78でやってみたら、short型の先頭bitが1の時は良さそうですが、0だと負の整数にならないようです。
(1)先頭bitが"<>"の時うまく負の数になる理由がわかりません。
一応、unsigned long型とlong型を共用体にする変数を作って対応しようと思ってますが
(2)その中でshort型の変数をunsigned short型にキャストしようと思いますが、これっていいのでしょうか?
NAKAさん、エビスクラウンです。追記します。
最初の投稿で負の数になる理由が分かりませんとの事でしたが、その理由は以下の通りです。
まず、演算時、整数型は整数の格上げにより、short型はint型に自動的に変換されます。もっとも、RL78はshort型とint型は同じサイズのなので、そのまま0x8000、2の補数で考えれば -32768 です。
次に演算を行う際は共通の型に揃えてから演算を行うと言う算術変換規則があり…
NAKAさん、こんにちは。NoMaYです。もし元のプログラムがそれでも動作していたのであれば、もう一度そもそもの仕様を確認した方法が良いと思うのです。よくあることですけれども、通信仕様書の記載が間違いで実際の動作が正しい(というのも何ですが)、かも知れません。あるいは、データ受信処理を抜けた後の次の過程で加工されている、かも知れません。通信仕様書を見ないまでも、以下の場合には、どういう仕様なのだろう?、という気掛かりが思い浮かびます。・ 符号ビット=1、残り16ビット=0xffff --> -1 or -0xffff ?自分の感覚的としては、このあたりのことだけであれば共用体は使わないと思います。こんな感じにすると思うのです。(キャストは不要かも知れないけれども、自分は毎日Cコードを書いているわけでは無くて詳細を暗記していなくて、、、)
if(符号ビット==0){ int32_t型変数 = uint16_t型変数{else{ int32_t型変数 = (int32_t)(0xffff0000 | (uint32_t)uint16_t型変数) とか int32_t型変数 = - (int32_t)uint16_t型変数 とか}
[追記] 2023/03/03 20:00この後のエビスクラウンさんのリプライで、さすがに上のコードはコメント不足ですよね、と思いましたので、以下にコメントだけ足しました。
if(符号ビット==0){ int32_t型変数 = uint16_t型変数{else{ int32_t型変数 = (int32_t)(0xffff0000 | (uint32_t)uint16_t型変数) ← 符号ビット=1、残り16ビット=0xffff --> -1 なら とか int32_t型変数 = - (int32_t)uint16_t型変数 ← 符号ビット=1、残り16ビット=0xffff --> -0xffff なら}
NAKAさん、NoMaYさん、エビスクラウンです。
横やりを入れるようで済みませんが、「良いか」の意味は、C言語仕様的に良いか、それともマイコンの仕様的に良いかのどちらでしょうか?
もし、C言語仕様的であれば、駄目です。理由はC言語は負の内部表現を決めておらず、符号付き型に対して、表現できない値を代入したり、キャストしたら、不定となるからです。つまり、16ビット符号付き変数に0x8000を代入した時点で言語仕様上は不定、0xffff0000より大きな値を符号付き32ビットの整数型にキャストしたときも言語仕様上は不定となります。
もっとも、マイコンはどれも2の補数で符号付き整数を扱いますから、「負の表現は2の補数に限定する」と言った条件下で考えるのであれば、「良い」と言うか、思った通りの結果となります。
short型をunsigned short型にキャストするのも同じ考えです。また、short型やunsigned short型は演算時、整数の格上げによって、int型またはunsigned int型になることも考慮すると、本件はかなり難しいです。やはり、元の仕様における通信で得られた下位側16ビットをshort型で扱っていることに無理がありそうです。
NoMaYさん、エビスクラウンです。
私もほぼ同じ結論に達しました。もともと符号付き整数型の負の内部表現を決めていない言語仕様で、17ビットの2の補数表現を扱うプログラムですから、かなり厄介です。ちなみにNoMaYさんの2つ目の計算式は値がおかしくなりませんか? 例えば、全ビット"1"の場合、uint16_t型の0xffffは65535ですから、それをint32_t型にキャストしても同じ65535、それの符号反転ですから、-1にはならず、-65535になりませんか?
なので、
if(符号ビット==0){ int32_t型変数 = uint16_t型変数{else{ int32_t型変数 = - (0x10000L - uint16_t型変数)}
になるかと思います。定数値はキャストではなく、接尾子にしました。
NAKAさん
上記の例は、あくまでも通信で得られる下位側16ビットをuint16_t型の変数に格納することが前提となっており、最初に記載されていた16ビット符号付き型の変数ではないことをご注意ください。
私もほぼ同じ結論に達しました。もともと負の内部表現を決めていない言語仕様で、17ビットの2の補数表現を扱うプログラムですから、ちょっと厄介です。ちなみにNoMaYさんの2つ目の式は正しい結果が得られますでしょうか(済みません、確認していません)。例えば、全ビットオール"1"の場合、下位側16ビットのuint16_t型の変数は0xFFFFの65535、それをint32_t型にキャストしても、同じ65535、それの符号反転ですから、-1にはならず、-65535では?
になるかと思います。なお、定数値はキャストではなく、接尾子にしました。
私とNoMaYさんの例は、あくまでも通信で得られた下位側16ビットを符号なし16ビットの変数に格納することが前提です。最初に記載されていた符号付き整数ではちょっと難しいかと思います。
次に演算を行う際は共通の型に揃えてから演算を行うと言う算術変換規則があり、これによりRL78の場合(int型が16ビットの場合)、unsigned long型との論理演算では、int型はunsigned long型に変換されます。ここで問題となるのは、負の値が格納されている値を符号なしの値に変換しなければならないことです。このルールはちゃんと規定されていて、その型の最大値+1から目的の値を減算した結果となります。つまり、4294967295+1-32768=4294934528、これを16進数にすると0xffff8000です。
だから、負の値の時は上手くいくのです。
エビスクラウンさん、こんにちは。NoMaYです。指摘ありがとうございます。2つあります。まず、RL78なのでintが16ビット幅である、ことを失念していました。ありがとうございます。他方、「とか」となっているのは、幾つか前のリプライの以下と対になっているのでした。> 通信仕様書を見ないまでも、以下の場合には、どういう仕様なのだろう?、という気掛かりが思い浮かびます。>> ・ 符号ビット=1、残り16ビット=0xffff --> -1 or -0xffff ?[追記]> もし元のプログラムがそれでも動作していたのであれば、もう一度そもそもの仕様を確認した方法が良いと思うのです。よくあることですけれども、通信仕様書の記載が間違いで実際の動作が正しい(というのも何ですが)、かも知れません。あるいは、データ受信処理を抜けた後の次の過程で加工されている、かも知れません。
NoMayさん、エビスクラウンさん いつもありがとうございます。 NAKAです。
金曜日なぜかカフェるねの更新がされず&後輩の問題に対応してたので確認が遅くなりました。
今、やってるのが仕様っていうのが無い状態で、ハードとソフトを触りながら、手探ってる状態です。
どうもAD4003っていう18bitのA/Dとbit数の異なるD/Aを共通のクロックでcsをコントロールしながら、タイミングで値を同じSPIで取ってる感じです。それでどうもA/Dの先端bitがタイミング的に取れないみたいで、SPIのMISOの信号を無理やりport入力して、csを制御したタイミング(微妙な調整がしてある)符号bitをportで取ってるみたいです。A/Dの前が差動入力になっていて、Vrefが中心電圧になっているようなのでプラス、マイナスの値があるようです。なので、符号bitに続くデータは単純に続きのデータだと思っています。デバイスはSAMV71という32bitのARMマイコンです。RL78は同じ動作をするか試しただけです。
もう一度、お二人のアドバイスを参考に、色々実験してみようと思います。
やっぱりThread Listの更新はかなり遅くなるのかな?
NAKAさん、こんにちは。NoMaYです。AD4003のマニュアルらしきものの日本語版のPDFを見てみたのですが、負の数、負数、符号、マイナス、とか検索してもヒットしなかったです。これってマイナスの値になるものでしょうか?他にも以下でもGoogle検索しましたが、思ったようには検索出来ませんでした。AD4003www.analog.com/jp/products/ad4003.htmlGoogle検索: AD4003 電圧 読み方www.google.com/search?q=AD4003+電圧+読み方
NAKAさん、こんにちは。NoMaYです。SAMV71というと、この案件でしょうか、、、読み返していて以下の文に気付いたところで思ったのですけれども、実は、負の数にならなくて、何と言うか、符号付きshort型は符号無しshort型をタイプミスしたバグなだけだった、といった顛末もちょっと気になり始めたのですけれども、、、、ソフト屋さんはソースさえあれば、だいたい理解できる?community-ja.renesas.com/cafe_rene/forums-groups/beginners/f/002-2095199602/9720/thread「別メーカ製品と書きましたが、実は開発品で本当は動作するのかも怪しい.....けど」
NoMayさん いつもありがとうございます。
説明に抜けがありましたが、マイナス電圧を印加してるのではなく
でVrefを2.5Vにしてあるため、1LSBだけ低い電圧入力時が0x3FFFFの認識です。
一応、ファンクション発信器で1Vp-p、2.5Voffsetの正弦波を入力して、A/D値を取得
エクセルでグラフ化すると、ちゃんと正弦波になってます。
一番初めの話で2.5Vより1.25V低い値を入力すると、正の数にならないか不安でした。その電圧を加えてほかの箇所が壊れないか確認しながらやってみます。よっぽど大丈夫だと思いまが・・・・・。
NAKAさん、こんにちは。NoMaYです。なるほど。理解しました。その表には気付きませんでした。
NAKAさん、こんにちは。NoMaYです。> なるほど。理解しました。その表には気付きませんでした。まてまてまて、自分。> マイナス電圧を印加してるのではなくならば、、、・ AD4003の入力 = 0V --> AD4003の出力 = 0x00000・ AD4003の入力 = 1LSB --> AD4003の出力 = 0x00001・ AD4003の入力 = 2.5V - 1LSB --> AD4003の出力 = 0x1ffff (条件Vref = 2.5V)のような?もし、マイナス電圧を印加しているならば、その場合には、、、・ AD4003の入力 = - 1LSB --> AD4003の出力 = 0x3ffff・ AD4003の入力 = - 2.5V --> AD4003の出力 = 0x20000 (条件Vref = 2.5V)のような?[追記]AD4003の入力、マイナス電圧、というのはIN+とIN-の差分の意味のつもりです。[追記]IN-をVref/2と同電位にしてあるのかな?
NoMaYさん NAKAです。混乱させてすみません!!
>IN-をVref/2と同電位にしてあるのかな?
⇒たしか?今回路図探してますが、どこいっちゃたかなぁ?
P.S.
ごめんなさぁ~~~い!!
NoMayさま ⇒ NoMaY大先生!だった!!m(__)m