기본적으로 wxWidgets에선 minGW나 Cygwin을 연동해서 사용하는 것들이 대부분이였다.

하지만, Windows에서 제대로 컴파일이 안되거나 적용이 안되는 문제점이 있는 부분이 있어서 수정하기 위해 연동하는 방법을 기록하도록 한다.

 

VS(Visual Studio)와 wxWidgets과정은 다음과 같다.

1. VS 설치

2. wxWidgets 소스 설치

 

여기서 VS 설치는 간단하게 MS 사이트에서 제공해주는 프로그램을 다운받아서 설치하면 된다.

https://visualstudio.microsoft.com/ko/downloads/

이미지 썸네일 삭제
Visual Studio Tools 다운로드 - Windows, Mac, Linux용 무료 설치

Visual Studio IDE 또는 VS Code를 무료로 다운로드하세요. Windows 또는 Mac에서 Visual Studio Professional 또는 Enterprise Edition을 사용해 보세요.

visualstudio.microsoft.com

이 사이트에 들어가면, 다음과 같은 페이지로 넘어가게 되는데.

여기서, 커뮤니티 혹은 Professional을 다운 받으면된다.

여기서 커뮤니티를 사용하면, 로그인으로 계속 갱신하면서 30일 평가판을 계속 쓸 수 있기 때문에

커뮤니티를 다운받는걸 추천한다.

대표사진 삭제

사진 설명을 입력하세요.

여기서 VS와 연동해야되는 이유는 MS 컴파일러를 사용해야되는 경우가 있어서(라이브러리가 MS 컴파일러만 지원해준다거나 하는 문제점이 있다면, 그걸 못 쓰는 경우도 있다.) MS 컴파일러를 지원 가능하다면, VS를 굳이 쓸 필요가 없다.

 

wxWidgets는 다음과 같은 사이트에 들어가면, 간단하게 다운 받을 수 있다.

여기서 wxWidgets는 기본적으로 MinGW 기준으로 작성되어 있는게 많기 때문에 소스를 다운 받는게 좋다.

https://www.wxwidgets.org/downloads/

Downloads - wxWidgets

Downloads Not using C++? Get wxWidgets from the wxPython , wxPerl , or wxHaskell download sites. When installing wxWidgets on Windows or macOS, we always recommend building the library from source yourself, and only provide the source package for most platforms. On some platforms, we have provided a...

www.wxwidgets.org

 

wxWidgets에서 Source Code에서 Window Zip이나 WIndow 7z을 다운받은 후에 압축을 풀어준다.

 

VS 설치 완료하고, wxWidgets의 source code를 다운 받았다면, 다음과 같은 과정을 거친다.

 

VS을 킨 후에 도구 > 명령툴 > 개발자 PowerShell 을 클릭해서 Powershell을 킨다.

 

다음과 같은 명령어를 작성한다.

cd <wxWidgets's Path>\wxWidgets-3.2.4\build\msw

nmake /f makefile.vc BUILD=release SHARED=1 TARGET_CPU=X86
 

 

여기서 nmake가 MS에서 지원해주는 Make 프로그램이다.

 

 

이걸 완료되면,

wxWidgets에 압축을 푼 곳에서 lib 파일에 vs_dll(SHARED=1)이나 vs_lib(SHARED=0)의 폴더가 발생하고, 필요한 라이브러리들이 완성된다.

여기서 BUILD는 release와 debug로 나뉘어지고, 컴파일할때, 사용되는 라이브러리를 말한다.

디버깅을 제대로 사용할려면, debug을 사용하는게 가장 좋다.

SHARED는 1과 0으로 TRUE와 FALSE로 나뉜다.

TRUE가 되면, 동적 라이브러리인 DLL형식으로 빌딩이 되는것이고, FALSE가 되면, 정적 라이브러리인 LIB형태로 빌딩이 된다.

TARGET_CPU는 사용되는 컴파일러에 따라서 달라지는데.

내가 잘못 설정했는진 모르겠지만, x86(32bit)만 컴파일이 제대로 되서, 이렇게 사용한다.

 

빌딩이 잘 되었다면, VS에서 프로젝트 아무거나 적용한 후에

속성을 들어가면, 속성 페이지에서 변경된다.

VS++ 디렉토리에서 '포함 디렉터리'에서 수정하는데.

'$(wxWidgets)\include\msvc;$(wxWidgets)\include'을 추가하면, MSVC에 header 파일과 included될 wxWidgets의 라이브러리를 호출이 가능하다.

여기서 중요한건 $(wxWIdgets)을 설정해야되는데.

wxWidgets을 설정하는건 '내 컴퓨터' '내 PC'에서 오른쪽 버튼을 눌러서 속성에 들어가. '고급 시스템 설정'에 들어간다.

 

 

이렇게 wxWidgets라는 변수에 wxWidgets를 설치한 경로를 설정하면, 문제 없이 처리하게 된다.

Posted by JunkMam
,

 PowerShell에서는 간단한 프로그래밍을 할 수 있다.
 간단한 프로그래밍을 이용하면, 간단한 장치나 동작을 시킬 수 있다.

 여기서 간단한 프로그래밍은 중복되는 파일이 있는지 확인하면서 삭제하거나 특정 위치로 옮기거나 실행시켜서 제거하는 장치를 만들 수 있다.

 

 그걸 하기 위해서 변하는 값을 저장하여 처리할 수 있어야 하며, PowerShell에서도 변수를 사용할 수 있다.

 

[PowerShell] 간단한 변수 생성.

 PowerShell에서 변수를 생성하기 위해선 '$'라는 기호를 사용해야 한다.

 

1
2
3
4
5
6
7
8
9
# 변수값을 정의 하기 위해서는 '$'를 사용해야한다.
$values = 0;
 
# 변수값을 숫자로 적용할 수 있다.
$123 = 0;
 
# 변수를 제거하는 명령어.
Remove-Variable values, 123;
 
cs

 

 

 변수를 사용하고, 제거하기 위해서는 PowerShell에서는 Remove-Variable이라는 함수를 사용해서 제거를 할 수 있다.

 변수 값을 제거해주지 않으면, PowerShell에 있는 변수를 재활용하지 않는 이상은 계속 쌓여서 메모리에 차지하는 문제점이 있다.

 

[PowerShell] PipeLine에 연결된 변수 사용법.

 참고 사이트: [MSDOC] PowerShell Pipelines
 PowerShell은 명령어 혹은 프로그램에서 출력되는 값을 받아들여서 다른걸로 재활용 할 수 있다.

 이것을 PipeLine이라고 하며, 다른 프로세서간의 통신을 연결해서 처리 할 수 있다.

1
2
3
4
5
6
# command1에 나온 결과물을 command2에 보내고, command2에 나온 결과물을 command3에 보낸다.
command1 | command2 | command3;
 
# list-item에서 나온 값을 출력하는 방법.(굳이 할 필요는 없다.)
ls | echo
 
cs

 여기서 PipeLine의 변수를 이용해서 제어를 할 수 있는데.

 이 제어하기 위해서 '$_'라는 변수형태를 취하게 된다.

1
2
3
4
5
6
7
8
9
# Text File 검색.
Get-ChildItem -Path *.txt |
# 개체 필터링.
  Where-Object {$_.length -gt 10000|
# 길이[파일 크기]에 맞춰서 정렬[오름차순]
    Sort-Object -Property length |
# 테이블 형태에 맞춰서 출력.
      Format-Table -Property name, length
 
cs

 

[PowerShell] 조건문

 PowerShell에서는 간단한 계산을 할 수 있지만, 알고리즘을 사용하기 위해서는 연산만 할 수 있으면 안된다.

 특정 조건에 맞춰서 참과 거짓으로 나뉘어져야하는데. 이 방법은 if문과 switch문을 이용해서 적용 할 수 있다.

 참고 사이트: [MSDOC] PowerShell 조건문 

[PowerShell] 간단한 if문 사용하기.

  if문은 참과 거짓을 사용할 수 있어야하므로, 2가지 경우를 사용할때 사용 할 수 있다.

 if문과 if-else문, if-else if문을 사용할 수 있다.

1
2
3
4
5
6
7
if(1 -eq 2){
 echo "True";
}elseif(1 -eq 2){
 echo "2=2";
}else{
 echo "False";
}
cs

 

[PowerShell] 간단한 Switch문 사용하기.

 PowerShell에서 if문을 사용하기에 분기가 많거나 하면, 거기에 맞춰서 처리하기 위해서 Switch문을 사용한다.

 

1
2
3
4
5
6
7
8
$switchValues = 0;
 
switch($switchValues){
    0 { $a = 1; }
    1 { $a = 2; }
#...
    default { $a = 0; }
}
cs

 

 

[PowerShell] 반복문.

 조건문 외에도 조건에 맞춰서

[PowerShell] 간단한 반복문 For문

1
2
3
4
5
#For문 적용.
for($i = 0$i -lt 100$i++){
    echo $i;
}
 
cs

 

 

[PowerShell] 간단한 반복문 ForEach문

1
2
3
4
5
6
#Foreach문 적용.
$folders = (Get-ChildItem -File *.txt);
foreach($folder in $folders)
{
    echo $folder.Name;
}
cs

 

[PowerShell] 간단한 반복문 While문

1
2
3
4
5
6
#while문 적용.
while($i -le 100){
    echo $i;
    $i+=1;
}
 
cs

 

[PowerShell] 조건에 적용할 비교문 방식.

-eq = equal

-ne = not equal

-le = least equal

-lt = least

-ge = great equal

-gt = great

 

-and = and

-or = or

-not = not

 

이렇게 맞춰서 비교문을에 적용 할 수 있으며, 비교문, 반복문의 조건을 적용할때 사용하면된다.

 

[PowerShell] 간단한 함수 생성.

참조 사이트: [MSDOC] 함수

반복적으로 동작하는 동작 방식을

1
2
3
4
5
6
7
8
9
10
11
# 함수 생성.
function addLines{
# 매개변수 저장.
    param (
        $paramHTMLFileName
    )
#함수 처리과정.
    "<p>`&nbsp`; <br/></p>" >> $paramHTMLFileName;
}
 
 
cs

 

[PowerShell] 간단한 예외 처리.

참조 사이트: [MSDOC]예외처리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 함수 생성.
function addHashDataLines{
    # 매개변수.
    param(
        $paramHTMLFileName,
        $paramAlgorithm,
        $paramTargetFileName
    )
    
    # 예외 처리.
    try{
        $hashData = Get-FileHash -algorithm $paramAlgorithm $paramTargetFileName;
        $algorithm = $hashData.Algorithm;
        $hash = $hashData.Hash;
        "<p>`&nbsp`; $algorithm : <br/></p>" >> $paramHTMLFileName;
        "<p>`&nbsp`; $hash <br/></p>" >> $paramHTMLFileName;
    }catch{
        echo "Error! Can't $paramTargetFileName is $paramAlgorithm Make File Hash!";
    }
}
 
cs

 

 

 

Posted by JunkMam
,

해당 방법은 다음 링크에 있는 내용을 보고 테스트한 후 확인한 것이다.

https://stackoverflow.com/questions/502002/how-do-i-move-a-file-to-the-recycle-bin-using-powershell

 

1
2
3
4
Add-Type -AssemblyName Microsoft.VisualBasic
[Microsoft.VisualBasic.FileIO.FileSystem]::DeleteFile('d:\foo.txt','OnlyErrorDialogs',
'SendToRecycleBin')
 
cs

 

 이렇게 하면,제대로 동작되는걸 확인했다.

 

'PowerShell' 카테고리의 다른 글

[PowerShell] PowerShell 간단한 사용법.  (0) 2023.01.01
Powershell에서 Progress 사용하기.  (0) 2020.07.03
Posted by JunkMam
,

 회사에서 Arduino를 이용해서 작업을 하다가.

 타이머를 사용하게 되었다.

 

 문제는 이 타이머를 사용하니.

 millis()와  delay()가 제대로 동작안되는 문제점이 생겼었다.

 

 한동안 이유를 못 찾은 상태로 지내다가 modbus_lib을 사용해야되는데.

 modbus_lib에선 millios()을 이용해서 통신되게 되어 있는데.

 

 millis()가 0이 계속 뜨니. 통신이 제대로 동작이 되지 않는다는 점이다.

 

 즉, 윗 문제를 해결해야만했다.

 

 그래서 찾아보니. millis()와 delay()sms Timer0에 영향을 받는다. 라고 설명이 되어 있다.

 이걸 보고, 타이머 2,3을 사용하는 곳에서 실수 한게 있는지 확인 하기 위해서 적용해봤다.

 

 

void setup()
{
TCCR2 = (1<<CS20) | (1<<CS21); // 간격 설정. CS 64 분배율.
TIMSK = (1<<TOIE2); // 오버 플로우 인터럽트 사용.
TCNT2 = 5; // 타이머 딜레이 250으로 동작하도록 설정.
TCCR3A = 0x00; // CTC를 적용하는 세팅.
TCCR3B = (1<<WGM32); // CTC를 적용하기 위한 세팅.
TCNT3 = 0; // 값 표시.
}
void loop()
{
Serial.println(millis(), DEC);
}


 여기서 TIMSK(Timer/Counter Interrupt Mask Register)를 이용해서 Timer2에서 OVF(Over Flow)가 발생할시 처리하게 만드는 것이 설정되었는데.

 

 TIMSK에서 Timer0를 설정한게 아닌. TIMSK를 설정이 잘못됨을 알았다.

 

 즉, Timer0의 설정이 기본적으로 설정되어 있었는데.

 이것을 TIMSK = (1<<TOIE2);를 사용해서 Timer0 세팅이 사라진 것이다.

 

 

void setup()
{
TCCR2 = (1<<CS20) | (1<<CS21); // 간격 설정. CS 64 분배율.
TIMSK = TIMSK | (1<<TOIE2); // 오버 플로우 인터럽트 사용.
TCNT2 = 5; // 타이머 딜레이 250으로 동작하도록 설정.
TCCR3A = 0x00; // CTC를 적용하는 세팅.
TCCR3B = (1<<WGM32); // CTC를 적용하기 위한 세팅.
TCNT3 = 0; // 값 표시.
}
void loop()
{
Serial.println(millis(), DEC);
}

 이렇게 수정하니. Timer0가 제대로 동작되어서 그래서, millis()에서 값이 이상없이 동작됨을 알 수 있었다.

 

 간단한 문제였지만, 제대로 확인 하지 않으면, 못 찾을 만한 것이다.

Posted by JunkMam
,

 

 

 PowerShell을 이용하면서 자주 문제 있던 부분이 반복문에서 어떻게 동작하고 있는지 알수 없어서 답답함이 없지 않아 있었다.

 

 특히 파일을 지우거나 하는 경우에 rm *을 하면, 어떤 파일이 어떻게 어느 시점에 지워지고, 얼마나 시간이 걸리는지 궁금한데.

 

 이걸 알 수 있는 방안이 전혀 없으니. 답답할 노릇이였다.

 

 그렇다고 탐색기를 이용해서 처리하기엔 GUI가 있으니. 부담도 있다고 할까.

 

 그래서 프로그래스(현재 동작하고 있는 상황을 표시하는 게이지 바)를 추가하고자 했다.

 

 참고 사이트에서는 MS에서 제공하는 PowerShell 도움말이다.

 

 나는 PowerShell-7을 기준으로 작성되어 있음을 참고하길 바란다.

 

 

foreach ( $i in 1..10 ) {
  Write-Progress -Id 0 "Step $i" -PercentComplete (($i / 10) * 100);
  foreach ( $j in 1..10 ) {
    Write-Progress -Id 1 -ParentId 0 "Step $i - Substep $j"  -PercentComplete (($j / 10) * 100);
    foreach ( $k in 1..10 ) {
      Write-Progress -Id 2  -ParentId 1 "Step $i - Substep $j - iteration $k" -PercentComplete (($k / 10) * 100) -SecondsRemaining 10;
      start-sleep -Millisecond 150
    }
  }
}

 

 여기서 사용되는 $i, $j, $k는 반복문에 사용되는 변수이고, 프로그래스를 출력하는 명령어는

 Write-Progress가 된다.

 

 위 소스를 사용하면,

 

 

 

 그림과 같이 된다.

 

 이걸 이용해서 프로그래스 바가 나오는데.

 

 여기서 -파란색 바가 증가하는 방법은

 -PercentComplete <Value>를 이용하면 되는것이고,

 

 시간을 표시하는 것은

 -SecondsRemaining <Value>를 사용하면 된다.

 

 

 이걸 이용해서 rm을 하는 것을 프로그래스로 표현할 수 있게 되는데.

 

 

$dirs = @();
$dirs += (Get-ChildItem -Directory);

$dirNumber = 0;
$dirPercent = 0;
$dirName = 0;
for($dirNumber = 0; $dirs.Length -gt $dirNumber; $dirNumber++)
{
    cd $dirs[$dirNumber].FullName;
    $dirName = $dirs[$dirNumber].Name;
   
    $dirLength = $dirs.Length;
    $dirPercent = ($dirNumber/$dirs.Length)*100;
   
    Write-Progress -Id 0 "DirName: $dirName : $($dirNumber+1)/$dirLength - $dirPercent%" -PercentComplete ($dirPercent);
   
    $files = (Get-ChildItem -File);
    $fileNumber = 0;
    $filePercent = 0;
    $fileLength = 0;
    $fileName = 0;
    if($files.Length -gt 0)
    {
      for($fileNumber = 0; $files.Length -gt $fileNumber; $fileNumber++)
      {
          $fileName = $files[$fileNumber].Name;
         
          $fileLength = $files.Length;
          $filePercent = ($fileNumber/$files.Length)*100;
          Write-Progress -Id 1 -ParentId 0 "ReMove FileName: $fileName : $($fileNumber+1)/$fileLength - $filePercent %"  -PercentComplete ($filePercent);
          rm -Force $files[$fileNumber];
      }
   
      Remove-Variable files, fileNumber, filePercent, fileLength, subDirs, fileName;
    }
   
    $subDirs = (Get-ChildItem -Directory);

    if($subDirs.Length -ne 0)
    {
      $dirs+=$subDirs;
    }
    else
    {
      cd ..;
      rm -Force $dirs[$dirNumber];
    }
}

Remove-Variable dirs, dirNumber, dirPercent, dirLength, dirName;




 이렇게 완성된다.

 

 

  DFS 알고리즘이 아니라. BFS을 이용한 방식이라서 Id 0의 프로그래스가 점점 증가하는 형태가 되지만, 잘 표시가 된다.

Posted by JunkMam
,

 회사에서 NAS를 얻었다. 하지만, 회사에서 공유기랑 내 자리가 멀리 있어서 공유기로 통해서 컴퓨터랑 연동하기가 힘든 상황이 만들어졌다.

 그래서, 컴퓨터에는 외부 네트워크로는 무선 네트워크로 정의하였다. NAS는 유선 LAN 밖에 연결을 할 수 없기 때문에 LAN과 컴퓨터랑 연결시킨다.

 이렇게 해도 NAS에 바로 붙지 앟는다. 그래서 네트워크 설정을 해줘야한다.
 네트워크설정 페이지에 들어가면,


 여기서 이더넷에서 속성을 들어가면, 다음과 같은 창이 띄워진다.


 여기서 인터넷 프로토콜 IPv4의 속성에 들어간다.


 가상으로 하는데. 여기서 NAS에서 설정한 인터넷 Class를 맞춘다.
 나는 192.168.1.x 로 네트워크 망을 설정한다.
 게이트웨이는 192.168.1.1로 잡힌 네트워크 망으로 NAS는 192.168.1.250으로 맞춰놨다.




 네트워크 망 설정이 끝나면,인터넷 연결 공유를 설정해주는것으로NAS와컴퓨터를 1:1로 연결하도록 한다.


 이 후에는 ipDisk Drive를 설치해서 연결해준다.
 여기서 문제가 발생할 수 있는게 인터넷 연결이 가끔 오작동 나는 경우가 있다. 그래서, 무선 인터넷 망을 우선으로 맞춰서 작업할 필요가 있다.

Posted by JunkMam
,

 

 회사에서 LoRa 통신을 하게 되었다.

 

 이걸 처리하기 위해서 예제 소스에 있는 라이브러리를 사용하기로 했다.

 

sandeepmistry/arduino-LoRa

An Arduino library for sending and receiving data using LoRa radios. - sandeepmistry/arduino-LoRa

github.com

 그런데, 여기서 문제가 발생했는데.

 LoRa 통신에서 초반에설정하는 코드인

  if (!LoRa.begin(915E6)) {             // initialize ratio at 915 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                       // if failed, do nothing
  }

 이 부분에서 문제가 발생하는 것이다.

 

 LoRa32u4에선 초기화가 되지 않고 루프가 걸리게 되어 있다.(Arduino와 LoRa Chip 따로 구해놓는다면, 연결을 제대로 한다면 문제가 없다.)

 

 이유는 다음 그림을 보면, 이해가 되는데.

 

 

이것은 LoRa32u4의 회로도이다.

 

 여기서 보면, 통신용(SPI로 통신한다.)의 Chip Select와 상태 피드백 등을 위해서 Modul 핀과 CPU 핀의 연결도를 표현되어 있다.

 

 그리고, 다음은 해당 라이브러리의 정의이다.

 

 

 이걸 보면, SS[Chip Select] pin과 RESET PIN, DIO0 PIN이 회로도랑 완전히 다르다는걸 알 수 있다.

 즉, 회로도와 라이브러리와의 관계가 맞지 않는 상태.

 

 이걸 맞추기 위해서 다음과 같이 수정한다.

 

 

 이렇게하면, PIN이 이상없이 동작되는 것을 확인 할 수 있다.

 

 해당 LoRa 라이브러리를 사용하다가 제대로 동작이 안되면, 고치길 바란다.

Posted by JunkMam
,
현재 회사에서 Adafruit SH1106이라는 Display 제품이라는 것을 사용하고 있다.
Adafruit SH1106 제품 사진
그리고, 제품 중에서 사용하고 있는 제품인 Adafruit MAX31865라는 제품이 있다.

 

이 제품을 동시에 사용하면서 컨트롤해야되는 상황이다.
하지만, 여기서 제대로 내용이 나오지 않고, 깨지는 현상 혹은 제대로 그래픽이 나오지 않는 현상이 발생하는데.
그것을 고칠려고 한다.

 

수정하기 전의 라이브러리는 다음과 같은 사이트에서 얻으면 된다.

 

 

 

오류라는 이유는 간단한데.
SPI는 CHIP SELECT를 이용해서 MOSI에 데이터들을 CLK에 맞춰서 받아들이게 되어 있다.
쉽게 말해서 데이터 통로는 1개이지만, CHIP SELECT로 여러개의 데이터를 받아들이는 형태이다.

 

여기서 MAX 31865의 SPI통신 방식과 SH1106의 SPI 통신 방식이 약간씩 차이가 나서 제대로된 화면이 출력이 안되거나 온도가 제대로 출력이 안되는 문제가 발생하는 것이다.
그러므로 SPI의 설정을 번갈아 가면서 처리해줘야한다.
주로 SPISettings를 이용하며, 이걸 SPITransaction이라고 한다.

 

SPITransaction이라는 것의 예제 소스를 보면 알겠지만.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <SPI.h>
 
// using two incompatible SPI devices, A and B. Incompatible means that they need different SPI_MODE
const int slaveAPin = 20;
const int slaveBPin = 21;
 
// set up the speed, data order and data mode
SPISettings settingsA(2000000, MSBFIRST, SPI_MODE1);
SPISettings settingsB(16000000, LSBFIRST, SPI_MODE3);
 
void setup() {
 // set the Slave Select Pins as outputs:
 pinMode (slaveAPin, OUTPUT);
 pinMode (slaveBPin, OUTPUT);
 // initialize SPI:
 SPI.begin();
}
 
uint8_t stat, val1, val2, result;
 
void loop() {
 // read three bytes from device A
 SPI.beginTransaction(settingsA);
 digitalWrite (slaveAPin, LOW);
 // reading only, so data sent does not matter
 stat = SPI.transfer(0);
 val1 = SPI.transfer(0);
 val2 = SPI.transfer(0);
 digitalWrite (slaveAPin, HIGH);
 SPI.endTransaction();
 // if stat is 1 or 2, send val1 or val2 else zero
 if (stat == 1) {
  result = val1;
 } else if (stat == 2) {
  result = val2;
 } else {
  result = 0;
 }
 // send result to device B
 SPI.beginTransaction(settingsB);
 digitalWrite (slaveBPin, LOW);
 SPI.transfer(result);
 digitalWrite (slaveBPin, HIGH);
 SPI.endTransaction();
}

 

SPI의 정보를 번갈아 가면서 처리하는 것을 알 수 있을 것이다.
settingsA와 settingsB을 번갈아가면서 동작해야되는게 SPI를 2가지 정보를 제대로 컨트롤 할 수 있는 방법이다.

 

여기서, OLED인 SH1106이 제대로 동작이 안된다. 라는 것을 언급했듯이.
SH1106이 제대로 동작이 되지 않는 특징이 있다.

 

그렇다면, 왜 SH1106이 동작을 하지 않는지 정확하게 어떤것이 다른지를 소스로 보고 알아보면.

 

1
2
3
4
5
#include <stdlib.h>
#include <SPI.h>
 
static SPISettings max31865_spisettings = SPISettings(5000000, MSBFIRST, SPI_MODE1);
MAX31865.cpp의 일부



1
2
3
#include "Adafruit_GFX.h"
#include "Adafruit_SH1106_changes.h"
 
SH1106.cpp의 일부
 

 

이렇게 SH1106은 SPI의 설정하는 변수가 존재하지 않는 것을 알 수 있다.

 

그리고 더 정확하게 오류나는 이유를 알려면, 메뉴얼을 보면 이해가 되는데.

 

MAX31865의 메뉴얼을 참조하면

 

다음과 같이 마지막에 failling일때, 데이터가 들어가기 때문이다.

 

SPI MODE의 표를 보고 분석한다면.

 

POL:
  • 0-클럭 idle이 low에서 출발
  • 1-클럭 idle이 high에서 출발
CPHA:
  • 0-시작 pulse에서 동작
  • 1-종료 pulse에서 동작

 

 

여기서 현상이 유사한건, MODE=1인 상태가 되어서
MAX31865는 MODE1으로 설정된 값으로 이동된다.

 

메뉴얼에서 보면, Data7부터 시작해서 8 Bit를 받고 있으므로
MSBFirst가 되는 것이다.
LSBFirst는 반대로 되어 있다.
간단하게 통신 관련되서 공부한 사람이라면, Big Endian과 Little Endian을 설정하는 거라고 보면 된다.

 

그 외 라이브러리에서 보면 알겠지만, 500kHz가 되어 있다.
이것도 메뉴얼에 살펴보면 이해가 되는데.

 

여기서 SCLK(클럭)의 최소 DC(0Hz)에서 5.0MHz라고 되어 있는것을 볼 수 있다.
이 사이에 데이터가 오갈 수 있다는 뜻이 되는것이다.

 

이유를 설정해준다고, MAX31865만을 설명을 계속 하게 된 것 같은데.
다음과 같이 SH1106의 데이터가 제대로 표시가 안되는 이유는 SPI의 설정이 달라서 일어나게 되어 있는것이다.
그래서, SH1106에 대해서 데이터를 송수신하기 위해서는 SH1106의 메뉴얼을 봐야한다.
Hz는 I²C만 제외하면 최소, 최대 Hz가 명확하게 안 밝혀져 있으니 무시하고.
이렇게 MSB가 먼저 나오는 MSBFirst인데.
Raising이 일어난 후에 데이터가 받아지는 것을 볼 수 있다.

 

즉, 데이터의 정보를 Rasing에 받도록 MODE를 설정해야되므로
MODE0가 SH1106에 적용이 된다는 것을 할 수 있다.
1
2
3
4
#include "Adafruit_GFX.h"
#include "Adafruit_SH1106.h"
 
static SPISettings SH1106_spisettings = SPISettings(8000000, MSBFIRST, SPI_MODE0);

 

다음과 같은 데이터를 설정하면 된다.
(참고로 8MHz는 SH1106의 설정을 보고 선택한 것으로 CLOCK의 분할 값이 1/2이,
AtMel2560(16MHz) 기준으로 보면, 8MHz가 맞다.)

 

이제, 이것을 데이터 송신할때마다 SPI Setting을 변경하도록 만들면 된다.
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void Adafruit_SH1106::SH1106_command(uint8_t c) {
 if (sid != -1)
 {
     SPI.beginTransaction(SH1106_spisettings);
   // SPI
   //digitalWrite(cs, HIGH);
   *csport |= cspinmask;
   //digitalWrite(dc, LOW);
   *dcport &= ~dcpinmask;
   //digitalWrite(cs, LOW);
   *csport &= ~cspinmask;
   fastSPIwrite(c);
   //digitalWrite(cs, HIGH);
   *csport |= cspinmask;
   SPI.endTransaction();
 }
 else
 {
   // I2C
   uint8_t control = 0x00;   // Co = 0, D/C = 0
   Wire.beginTransmission(_i2caddr);
   WIRE_WRITE(control);
   WIRE_WRITE(c);
   Wire.endTransmission();
 }
 
}
 

 

여기서 SPI.beginTransaction()을 사용하여 SPI의 세팅을 변경해서 송신할 준비를 하도록 만드는 것이고,
SPI.endTransaction()을 사용하여 데이터를 송신하도록 하면 문제가 없게 된다.
Posted by JunkMam
,
 현 직장에서 SH1106을 사용하게 되었는데.
 보드가 설정되었던게 Arduino 라이브러리에서 핀 번호로 할당되지 않는 핀이 적용된 상태이다.(Atmel 2560)
 하지만, Adafruit_SH1106의 라이브러리에선 생성자에서 수정이 되는 제품이 없는 것이다.
 
1
2
3
4
5
6
class Adafruit_SH1106 : public Adafruit_GFX {
 public:
  Adafruit_SH1106(int8_t SID, int8_t SCLK, int8_t DC, int8_t RST, int8_t CS);
  Adafruit_SH1106(int8_t DC, int8_t RST, int8_t CS);
  Adafruit_SH1106(int8_t RST);
}
cs

 생성자를 보면, SID(슬레이브 ID)와 SCLK(시리얼 통신 클럭 핀), DC(데이터/컨트롤 핀), RST(리셋 핀), CS(칩 셀렉트 핀)을 설정하도록 되어 있다.
 그리고, 이 설정된 핀의 번호를 보고 해당 레지스터의 위치를 찾아서 수정하도록 되어 있는 상태인데.
 이것이 불만족스러웠다.(특히, 지금 Atmel 2560의 데이터를 전부 다 사용하도록 만든 보드를 사용하는 회사 보드 입장에선 라이브러리가 불만인 상황...)

1
2
3
4
    csport      = (PortReg*)portOutputRegister(digitalPinToPort(cs));
    cspinmask   = digitalPinToBitMask(cs);
    dcport      = (PortReg*)portOutputRegister(digitalPinToPort(dc));
    dcpinmask   = digitalPinToBitMask(dc);
cs

 그래서, 해당 라이브러리에서 레지스터를 다이렉트로 연결해서 사용하도록 만들어 봤다.(굳이 이렇게 하지 않고, 해당 핀 번호 혹은 레지스트 연결하는 하위 함수를 아시는 분들은 매크로를 사용해서 수정하면 된다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  /*
   @function : setCsPort
   @arg : PortReg* port(레지스트의 동작을 설정하는 변수)
   @arg : PortReg* portOpen(레지스트 초기화 하기 위한 변수)
   @arg : csPin(값 설정)
  */
  void setCsPort(PortReg* port, PortReg* portOpen, uint8_t csPin);
 
  
 
  /*
   @function : setDcPort
   @arg : PortReg* port(레지스트의 동작을 설정하는 변수)
   @arg : PortReg* portOpen(레지스트 초기화 하기 위한 변수)
   @arg : csPin(값 설정)
  */
  void setDcPort(PortReg* port, PortReg* portOpen, uint8_t dcPin);
 
  
 
  /*
   @function : setRestPort
   @arg : PortReg* port(레지스트의 동작을 설정하는 변수)
   @arg : PortReg* portOpen(레지스트 초기화 하기 위한 변수)
   @arg : csPin(값 설정)
  */
  void setRestPort(PortReg* port, PortReg* portOpen, uint8_t restPin, bool rest = true);
 
  
 
  /*
   @function : init
   @설명 : 
   begin()의 함수를 다시 재설정하기 위해서 동작 시키는 함수.
  */
  void init(uint8_t switchvcc = SH1106_SWITCHCAPVCC, uint8_t i2caddr = SH1106_I2C_ADDRESS);
cs

이렇게 header파일를 수정했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
void Adafruit_SH1106::setCsPort(PortReg* port, PortReg* portOpen, uint8_t mask)
{
    csport = port;
    *portOpen |= mask;
    cspinmask = mask;
}
 
void Adafruit_SH1106::setDcPort(PortReg* port, PortReg* portOpen, uint8_t mask)
{
    dcport = port;
    *portOpen |= mask;
    dcpinmask = mask;
}
 
void Adafruit_SH1106::setRestPort(PortReg* port, PortReg* portOpen, uint8_t mask, bool rest)
{
    restport = port;
    *portOpen |= mask;
    restpinmask = mask;
    
    if(rest)
    {
        *restport |= restpinmask;
        delay(1);
        *restport &= ~restpinmask;
        delay(10);
        *restport |= restpinmask;
    }
}
 
void Adafruit_SH1106::init(uint8_t vccstate, uint8_t i2caddr)
{
    sid = 0;
    hwSPI = true;
    
    if (hwSPI){
        SPI.begin ();
        #ifdef __SAM3X8E__
            SPI.setClockDivider (9); // 9.3 MHz
        #else
            SPI.setClockDivider (SPI_CLOCK_DIV2); // 8 MHz
        #endif
    }
    #if defined SH1106_128_32
    // Init sequence for 128x32 OLED module
    SH1106_command(SH1106_DISPLAYOFF);                    // 0xAE
    SH1106_command(SH1106_SETDISPLAYCLOCKDIV);            // 0xD5
    SH1106_command(0x80);                                  // the suggested ratio 0x80
    SH1106_command(SH1106_SETMULTIPLEX);                  // 0xA8
    SH1106_command(0x1F);
    SH1106_command(SH1106_SETDISPLAYOFFSET);              // 0xD3
    SH1106_command(0x0);                                   // no offset
    SH1106_command(SH1106_SETSTARTLINE | 0x0);            // line #0
    SH1106_command(SH1106_CHARGEPUMP);                    // 0x8D
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x10); }
    else
    { SH1106_command(0x14); }
    SH1106_command(SH1106_MEMORYMODE);                    // 0x20
    SH1106_command(0x00);                                  // 0x0 act like ks0108
    SH1106_command(SH1106_SEGREMAP | 0x1);
    SH1106_command(SH1106_COMSCANDEC);
    SH1106_command(SH1106_SETCOMPINS);                    // 0xDA
    SH1106_command(0x02);
    SH1106_command(SH1106_SETCONTRAST);                   // 0x81
    SH1106_command(0x8F);
    SH1106_command(SH1106_SETPRECHARGE);                  // 0xd9
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x22); }
    else
    { SH1106_command(0xF1); }
    SH1106_command(SH1106_SETVCOMDETECT);                 // 0xDB
    SH1106_command(0x40);
    SH1106_command(SH1106_DISPLAYALLON_RESUME);           // 0xA4
    SH1106_command(SH1106_NORMALDISPLAY);                 // 0xA6
    #endif
 
    #if defined SH1106_128_64
    // Init sequence for 128x64 OLED module
    SH1106_command(SH1106_DISPLAYOFF);                    // 0xAE
    SH1106_command(SH1106_SETDISPLAYCLOCKDIV);            // 0xD5
    SH1106_command(0x80);                                  // the suggested ratio 0x80
    SH1106_command(SH1106_SETMULTIPLEX);                  // 0xA8
    SH1106_command(0x3F);
    SH1106_command(SH1106_SETDISPLAYOFFSET);              // 0xD3
    SH1106_command(0x00);                                   // no offset
    
    SH1106_command(SH1106_SETSTARTLINE | 0x0);            // line #0 0x40
    SH1106_command(SH1106_CHARGEPUMP);                    // 0x8D
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x10); }
    else
    { SH1106_command(0x14); }
    SH1106_command(SH1106_MEMORYMODE);                    // 0x20
    SH1106_command(0x00);                                  // 0x0 act like ks0108
    SH1106_command(SH1106_SEGREMAP | 0x1);
    SH1106_command(SH1106_COMSCANDEC);
    SH1106_command(SH1106_SETCOMPINS);                    // 0xDA
    SH1106_command(0x12);
    SH1106_command(SH1106_SETCONTRAST);                   // 0x81
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x9F); }
    else
    { SH1106_command(0xCF); }
    SH1106_command(SH1106_SETPRECHARGE);                  // 0xd9
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x22); }
    else
    { SH1106_command(0xF1); }
    SH1106_command(SH1106_SETVCOMDETECT);                 // 0xDB
    SH1106_command(0x40);
    SH1106_command(SH1106_DISPLAYALLON_RESUME);           // 0xA4
    SH1106_command(SH1106_NORMALDISPLAY);                 // 0xA6
    #endif
    
    #if defined SH1106_96_16
    // Init sequence for 96x16 OLED module
    SH1106_command(SH1106_DISPLAYOFF);                    // 0xAE
    SH1106_command(SH1106_SETDISPLAYCLOCKDIV);            // 0xD5
    SH1106_command(0x80);                                  // the suggested ratio 0x80
    SH1106_command(SH1106_SETMULTIPLEX);                  // 0xA8
    SH1106_command(0x0F);
    SH1106_command(SH1106_SETDISPLAYOFFSET);              // 0xD3
    SH1106_command(0x00);                                   // no offset
    SH1106_command(SH1106_SETSTARTLINE | 0x0);            // line #0
    SH1106_command(SH1106_CHARGEPUMP);                    // 0x8D
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x10); }
    else
    { SH1106_command(0x14); }
    SH1106_command(SH1106_MEMORYMODE);                    // 0x20
    SH1106_command(0x00);                                  // 0x0 act like ks0108
    SH1106_command(SH1106_SEGREMAP | 0x1);
    SH1106_command(SH1106_COMSCANDEC);
    SH1106_command(SH1106_SETCOMPINS);                    // 0xDA
    SH1106_command(0x2);    //ada x12
    SH1106_command(SH1106_SETCONTRAST);                   // 0x81
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x10); }
    else
    { SH1106_command(0xAF); }
    SH1106_command(SH1106_SETPRECHARGE);                  // 0xd9
    if (vccstate == SH1106_EXTERNALVCC)
    { SH1106_command(0x22); }
    else
    { SH1106_command(0xF1); }
    SH1106_command(SH1106_SETVCOMDETECT);                 // 0xDB
    SH1106_command(0x40);
    SH1106_command(SH1106_DISPLAYALLON_RESUME);           // 0xA4
    SH1106_command(SH1106_NORMALDISPLAY);                 // 0xA6
    #endif
 
    SH1106_command(SH1106_DISPLAYON);//--turn on oled panel
}
 
cs

추가한 함수를 정의한 내용.
이렇게 사용하여, 다음과 같은 방식으로 추가하면, 제대로 동작을 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <Adafruit_GFX.h>
 
#include <Adafruit_SH1106_changes.h>
 
#define OLED_RESET -1
 
//Adafruit_SH1106 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
 
Adafruit_SH1106 display(OLED_RESET);
 
void setup()   {
 
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
 
  display.begin(SH1106_SWITCHCAPVCC);
 
  
 
  // init done
 
  display.setCsPort(&PORTH, &DDRH, B00100000);
 
  display.setDcPort(&PORTG, &DDRG, B00001000);
 
  display.setRestPort(&PORTG, &DDRG, B00010000);
 
  display.init(SH1106_SWITCHCAPVCC);
 
}
 
cs
 
이렇게 Arduino 파일에 적용해서 사용할 수 있게 된다.
 
SPI에서 MOSI와 MISO는 자체적으로 고정된 핀을 사용하므로, CS핀과 Reset핀, DC핀 중에 숫자핀이 없다면, 사용하는 것이 좋다.
 
여담으로 오랜만에 티스토리에 포스팅하는데 에디터가 참, 안좋게 바뀐 것 같다.
특히, ColorScript의 클립보드 붙여넣기가 제대로 동작이 안되서 불편함이 이만저만이 아니다.

 

Posted by JunkMam
,

libmingwex-0.dll 이라는게 없다고 하면서 오류가 나는 경우가 있다.


이럴때 해결하는 방법은 MinGW가 있는 lib에서 libmingwex-0.dll을 넣어서 관리하거나, 다음과 같은 방식을 사용한다.



프로젝트에서 Build options을 추가한다.



이렇게 창이 뜨는데, 여기서 Linker settings(정적 라이브러리를 연결하는 창)에 들어가서 libmingwex.a을 추가한다.



이렇게 해서 컴파일을 사용할 수 있게 된다.


명령어로 한다면, 

'mingw32-g++.exe  -o bin\Release\Test.exe obj\Release\main.o  -s  MinGW\lib\libmingwex.a'


이렇게 하면 추가되어서 컴파일이 된다.

Posted by JunkMam
,