2017年8月16日 星期三

CPP 如何引入 C 檔使用

C++ 如何引入 C 檔使用

指令 extern “C” { }

這個指的意思其實就是用C的方式來編譯函式或變數,假如說有一個
void fun(int, int);
C++編譯之後會得到一串名稱為 _fun_int,_int
但是 C 編譯之後只會得到名稱為 _fun
這裡也就就指出了為什麼 C++ 可以多載的原因了。


C++ 引入 C 檔案

如果一份C寫了之後打算給C++使用,就在他的檔頭前後加上這六段即可
// cFile.h

#ifdef  __cplusplus
extern "C" {
#endif

/* 代碼 */

#ifdef  __cplusplus
}
#endif
其實C++ 很大程度的兼容,也可以連考慮都不考慮直接加上就好


C 引入 C++ 檔案

與上面相同


參考

2017年8月10日 星期四

stm32f469i GUI 如何放入自訂圖片 如何轉換圖檔給stm讀取

stm32f469i GUI 如何放入自訂圖片 如何轉換圖檔給stm讀取

打開這一份範例:
STM32Cube_FW_F4_V1.16.0\Projects\STM32469I-Discovery\Examples\LCD_DSI\LCD_DSI_CmdMode_DoubleBuffering
預設有兩張圖片,這兩張個別是
  • image_320x240_argb8888
  • life_augmented_argb8888
放置的位置在
LCD_DSI_CmdMode_DoubleBuffering\Inc
他是一份 .h 檔案定義了這張圖片,裡面長這個樣子
const uint32_t life_augmented_argb8888[76800] =
{
0xFFFFFFFF,
0xFFFFFFFF,
...
};
這裡就是圖片的像素質了,兩個兩個一組看,第一組FF是透明度,越大越不透明,再來個別是 R, G, B 依序比如說一個顏色的 RGB 是 50, 100, 150 對應到的格式就是 0xFF326496。
我寫了一個轉換程序,可以把 BMP 圖檔轉換到 .h 檔,需要的可以參考。
Bmp_to_ARGB888
使用方式直接拉BMP圖檔到解壓縮出來的 exe 上然後放開即可(可以一次拉好幾個進去)。
圖檔只能放exe旁邊(寫的時候沒注意到的小Bug)
或者使用CMD指令(一樣要放一起)
Bmp_to_ARGB888.exe p1.bmp p2.bmp

2017年8月8日 星期二

stm32f4 使用計時器計時 1ms

stm32f4 使用計時器計時 1ms

可以使用官方範例程式內的 Examples\TIM\TIM_TimeBase 修改
預設是 delay 1s 修改一下參數 Period 除以 1000 即是 1ms
初始化計時器
void timers_init()
{
    uint32_t time_c = 10000;
    uwPrescalerValue = (uint32_t)((SystemCoreClock / 2) / 10000) - 1;
    TimHandle.Instance = TIMx;
    TimHandle.Init.Period = 10000/1000 - 1 ;
    TimHandle.Init.Prescaler         = uwPrescalerValue;
    TimHandle.Init.ClockDivision     = 0;
    TimHandle.Init.CounterMode       = TIM_COUNTERMODE_UP;
    TimHandle.Init.RepetitionCounter = 0;

    if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    {
        Error_Handler();
    }

    if(HAL_TIM_Base_Start_IT(&TimHandle) != HAL_OK)
    {
        Error_Handler();
    }
}
這裡這樣設置就可以了,再來它會自動每 1ms 呼叫 HAL_TIM_PeriodElapsedCallback() 這個函式,這個函式這樣寫
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    static int timer1 = 0;
    static int timer2 = 0;
    ++timer1;
    ++timer2;

    if(timer1 == 1000) {
        BSP_LED_Toggle(LED1);
        timer1 = 0;
    }

    if(timer2 == 500) {
        BSP_LED_Toggle(LED2);
        timer2 = 0;
    }
}
即可用不同頻率閃爍LED了,我不確定中斷程序會不會等這個函式執行完畢;建議用一個全域變數當flag,讓計時器激活他,然後由主函式內的 while 統一控管來處理,不然可能會卡住導致延遲。

Keil uVision 5 查看變數出現 無法查看

Keil uVision 5 查看變數出現 無法查看

因為預設編譯器是優化全開 -O3 某些變數被優化掉就看不到了,暫時先關閉優化就好了
先進入專案選項內
選擇 -O0
再來須要全部重新編譯 F7,需要花點時間,編譯完畢之後使用
F10 (跳過fun) 或 F11(行執行) 來跑程式跑到你要的位置
你可以把滑鼠移動到變數上查看,也可以從右下角查看區域變數。

2017年8月6日 星期日

如何改 Windows 10 桌面右鍵的選單內容的快捷鍵

如何改 Windows 10 桌面右鍵的選單內容的快捷鍵

先按一下開始直接打字搜尋 regedit 進入登錄檔編輯器
接著在上面的路徑輸入,舊版的沒有上面那一條好像自己慢慢點進去
電腦\HKEY_CLASSES_ROOT\Local Settings\MuiCache
再來一路開進去
這邊以 VS 為例,點兩下進去把
在 Visual Studio 中開啟(&V),後面的V改成你要的任意快捷鍵就可以了。

2017年7月31日 星期一

Markdown HackMD Github 同一頁文內跳轉

Markdown HackMD Github 同一頁文內跳轉

使用超連結跳轉即可

HackMD

在 HackMD 內大標題中標題小標題都會自己有一個標籤
比如說一個大標籤
# 第一章
## 第一節
相對應的跳轉方式就是
- [第一章](#第一章)
- [第一節](#第一節)

Github

這個就沒有Markdown自己擴展的連結,只能自己用html補
<h2 id="First">第一章</h2>
相對應的跳轉方式就是
- [第一章](#First)

STM32F469I GPIO 基本的閃爍與按鈕控制

STM32F469I GPIO 基本的閃爍與按鈕控制

板子上現成的 LED 與按鈕對應的 GPIO 腳位

LED1 G6
LED2 D4
LED3 D5
LED4 K3
按键 A0

函式解說

延遲函式,這個內建沒有我們自己弄一個
void delay(){
  int i;
  for(i=0; i<0xffffff; ++i);
}
如果需要精準的時間延遲可以參考這一篇站內連結
STM32 (F469I) 延遲時間 如何精準的計算

初始化

HAL_Init();
BSP_LED_Init(LED1);
這裡的LED1是對應到這張板子的正面的LED1

使用函式

關燈
HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_PIN , GPIO_PIN_RESET);
開燈
HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_PIN , GPIO_PIN_SET);

範例代碼

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  BSP_LED_Init(LED1);

  while(1)
  {
    delay();
    HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_PIN , GPIO_PIN_RESET);
    delay();
    HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_PIN , GPIO_PIN_SET);
  }
}

詳細代碼

如果不用內建函式LED1的字樣的話完整的打法是這樣
下面的範例是 B4 ,第一行就是改成4,第二行與第三行的 GPIO 後面改為B
  uint16_t pin = GPIO_PIN_4;
  GPIO_TypeDef* port = GPIOB;
  __HAL_RCC_GPIOB_CLK_ENABLE();

  GPIO_InitTypeDef  GPIO_InitStruct;
  GPIO_InitStruct.Pin = pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
  HAL_GPIO_Init(port, &GPIO_InitStruct);
  HAL_GPIO_WritePin(port, pin, GPIO_PIN_SET);

GPIO所有腳位的位置

查看手冊 STM32F469 Discovery user manual.pdf 這一份文件內的資料
第17頁與18頁有提到對應MCU那些腳位
背板腳位 實際腳位
D15 PB8
D14 PB9
D13 PD3
D12 PB14
D11 PB15
D10 PH6
D9 PA7
D8 PG10
D7 PG11
D6 PA6
D5 PA2
D4 PG12
D3 PA1
D2 PG13
D1 PG14
D0 PG9

參考

STM32 (F469I) 延遲時間 ms us 如何精準的計算

STM32 (F469I) 延遲時間 如何精準的計算

如何利用系統內的時間 SysTick 來延遲 STM32 下面是一個示範的例子。
時脈的設定在函式內,這裡示範的時脈是 180Mhz,你可以從官方的範例代碼,隨便一個應該都有,可以看到註解會明顯地寫著 180Hhz 等字樣。
這篇介紹的是比較簡單的delay方式,但這會導致計時中板子CPU停機不工作,如果需要多個LED不同頻率閃爍藥用中斷計時比較好,參考站內連結stm32f4 使用計時器計時 1ms

初始化系統時間函式

SystemClock_Config();

調用系統函式

HAL_Delay(1000);

自訂函式

如果需要1us就把乘以1000給拿掉就可以了。
/*****************************************************************
Name : 毫秒延遲
Date : 2017/07/31
By   : CharlotteHonG
Final: 2017/07/31
*****************************************************************/
void delay_ms_core(uint32_t n) {
  uint32_t clk = 180;               // CPU 180MHz
  uint32_t ticks = time_ms * clk * 1000;  // time is ms
  uint32_t told = SysTick->VAL;
  uint32_t tnow = told;
  uint32_t tcnt = 0;
  for(; tcnt<ticks; tnow=SysTick->VAL)
  {
    if(tnow != told) {
      if(tnow < told) {
        tcnt += told - tnow;
      } else { 
        tcnt += SysTick->LOAD-tnow + told;
      } told = tnow;
    }
  }
}
搞得這麼麻煩是為了避開益位的問題
SysTick 是一個倒數的計時器,歸零之後會從SysTick->LOAD 重新開始倒數,一般來說這個數值會是 SystemCoreClock 我的板子是 16M。
這些數值在執行 HAL_Init(); 的時候會幫你設置好,你也可以從這個函式按F12慢慢追上去就可以追到這些數據了。
if(tnow != told) 是為了確保你的累加量總是小於 16M,不然如果益位超過2次你就沒辦法計算到底是多少了。每次變動後 told = tnow; 重新計算變量。
if(tnow != told) 是一般正常情況就是相減就可以得到時間變量了
else 是益位後的處理,大概是這麼算的已知總長是16M,當時間為 10(told) 被記錄到,經過一段時間變成15M(tnow),要計算其變量就是 16M - 15M(tnow) +10(told)。
就是10歸零之後又減少1M的意思了。

時間常數超出範圍

使用的時候要注意不能設太大,否則ticks可能會相乘出來會超過參數上的 uint32_t 的最大值,處理方式簡單再加一層 for 迴圈處理,依此類推自己加大時間單位。
void delay_ms(uint32_t t) {
  const uint32_t sec = 1000;
  for(; t>=sec; t-=sec) {
    delay_ms_core(sec);
  } delay_ms_core(t);
}


參考

2017年7月26日 星期三

git branch 基礎操作流程

git branch rebase 操作流程指令

如果需要共同作者一起開發的話,一定會用到分支的功能,假設是兩個人的狀態下會需要三個分支。
  • 主分支
  • 作者A
  • 作者B

指令懶人包

新增br1分支
 git branch br1
切到br1分支
git checkout br1
如果分支尚未建立可以加入 -b 切換同時創造
git checkout -b br1
合併過程
# 先切到br1分支
git checkout br1

# 分支自己與主線先行合併
git rebase master

# 這時候看代馬可能會有衝突瀏覽一下修正所有衝突(這裡注意不要馬上用 commit 提交了)
git add *

# 修復衝突繼續衍合
git rebase --continue
# 到這裡完成了你自己的分支與主線整合

# 切回主線合併
git checkout master
git merge br1
合併到主線了,這麼做有個好處是合併的產生的衝突由該分支的作者自己處理,處理完之後也可以決定要不要並回去;而不是直接 merge 把責任交給主作者去看了。

2017年7月21日 星期五

OpenCV 3.2.0 的擴充 Contrib 函式庫如何編譯 與 使用 (Visual Studio)

OpenCV 3.2.0 的擴充 Contrib 函式庫如何編譯 與 使用 (Visual Studio)

關於一般的使用可以參考站內文章:OpenCV 3.2.0 vc14 如何安裝在 Visual Studio 2017
OpenCV 從第三版開始就把一些函式庫拆出來放到 Contrib 上如果要使用要自己重新編一次整份,這個編譯一次要1~2小時左右建議沒用到直接參考文內使用官方幫你編好的。

導航

  • 下載
  • CMAKE 產生編譯檔案
  • MAKE 編譯檔案
  • 建立檔案

下載

記得版本就下對,我第一次使用的時候版本錯了,一直出現錯誤找不到原因
cmake 會彈出 error configuring process, project files may be invalid 的錯誤信息
出現這個八成是版本錯了或者是沒有使用圖形介面選路徑(這個應該是cmake的bug)
版本從這裡選擇不要直接傻傻的下~
懶人包連結:
如果有安裝 Git 可以直接打指令省下解壓縮時間與空間

git clone -b 3.2.0 https://github.com/opencv/opencv

git clone -b 3.2.0 https://github.com/opencv/opencv_contrib
沒有的話按右邊下載zip檔案下來把兩個都下載下來

下載 cmake

根據自己的作業系統選擇正確的版本
安裝的時候創建一下捷徑與環境變數


CMAKE

打開之後最上面兩個路徑,第一個是opencv的路徑,如果是用 git 下載的就是選到下載的解壓後的資料夾,如果是從官方下載的選到source資料夾;
第二個是編譯後的路徑,選到你喜歡能夠找到的位置即可,記得創個空資料夾包起來。
(圖中我是從git下載的,如果下載zip資料夾名會多版本號)
先按左下角configure,然後跳出要你選編譯器,選你正在用的版本;注意圖中有個Win64建議選64位元的,效能較佳。
這邊第一次可能會卡一下,第一次時需要從網路下載缺失的套件,記得連網。
找到 ,輸入你下載的 opencv_contrib 中的 modules。注意這裡不能貼上路徑會出錯,一定要按右邊按鈕選路徑(軟件bug)。
然後再按一下 configure ,第二次如果會出錯,看一下上面提到的。
接著按一下 Generate 就完成了,右邊 Open Project 可以直接打開;如果你有多個 Visual Studio 最好手動打該正確的版本,按一下打開專案,然後再找到路徑內的專案打開,再來別急著自己按。
對著專案按右鍵重建方案,準備好在按這裡會編譯很久且途中不能反悔關不掉;我自己實測i7 4790K約15~20分、i5 4460會到1小時。
這裡我是使用Debug模式重建,如果你需要使用Release模式編譯OpenCV需要在這裡選擇;兩個都需要就要個別編譯一次!
建好之後檢查一下底下有沒有錯誤
最後對著INSTALL按下僅限專案->僅建置INSTALL
完成編譯了,只剩下使用。

如何使用 OpenCV

之後找到install這個資料夾,留這個即可剩下的都可以砍了
把名稱更改為 OpenCV320_VC15 放到C槽底下
再來下載兩個批次檔:https://mega.nz/#F!B993FSKJ!NZ2YRRUGSb9r4JQQyHslpw
把AddPath放到這裡來運行(這個只是新增bin到環境變數)
把CreatList放到這裡點兩下運行,會多出兩個文字文件,先把他打開放著。(這個只是取得這個資料夾內所有 .lib 檔名稱)
打開你 Debug 可以看到這裡的檔案每個檔名結尾都有一個d表示是Debug模式用的,沒有Debug是給Release用的,因為這裡還沒編譯打開查看會是空的。


專案的建設

先開一份空專案
貼上測試的代碼:
/**********************************************************
Name :
Date : 2016/05/29
By   : CharlotteHonG
Final: 2016/05/29
**********************************************************/
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace cv;

int main(int argc, char const *argv[]) {
    /* 畫布 */
    Mat img(270, 720, CV_8UC3, Scalar(56, 50, 38));
    /* 直線 */
    line(img, Point(20, 40), Point(120, 140), Scalar(255, 0, 0), 3);
    /* 實心方塊 */
    rectangle(img, Point(150, 40), Point(250, 140), Scalar(0, 0, 255), -1);
    /* 實心圓 */
    circle(img, Point(330, 90), 50, Scalar(0, 255, 0), -1);
    /* 空心橢圓 */
    ellipse(img, Point(460, 90), Size(60, 40), 45, 0, 360, Scalar(255, 255, 0), 2);
    /* 不規則圖形 */
    Point points[1][5];
    int x = 40, y = 540;
    points[0][0] = Point(0 + y, 50 + x);
    points[0][1] = Point(40 + y, 0 + x);
    points[0][2] = Point(110 + y, 35 + x);
    points[0][3] = Point(74 + y, 76 + x);
    points[0][4] = Point(28 + y, 96 + x);
    const Point* ppt[1] = { points[0] };
    int npt[] = { 5 };
    polylines(img, ppt, npt, 1, 1, Scalar(0, 255, 255), 3);
    /* 繪出文字 */
    putText(img, "Test Passed !!", Point(10, 230), 0, 3, Scalar(255, 170, 130), 3);
    /* 開啟畫布 */
    imshow("OpenCV Test By:Charlotte.HonG", img);
    waitKey(0);
    return 0;
}
修改屬性(先確認上方模式 Debug - x64 要是對的)
加入include目錄
加入lib目錄
加入lib檔案
目錄底下每個lib都要打上來(剛剛打開的文件夾可以一次複製全部)
然後就完成了
接下來你可以考慮把剛剛的模式改為Release模式在重新編譯一次;接著把檔案重新複製到C曹執行剛剛重複的步驟,就可以獲得兩個版本的檔案了,其中只需要注意引入的dll檔案,這裡我已經幫你把檔案清待分開了,在不同的模式輸入不同的清單即可。


其他補充 - 快速流程

  1. 下載指令替代
  2. Cmake部分其實可以用指令替代
  3. 指令開啟專案 -> CTRL+SH+B -> 換Release版本在一次
  4. 對著 INSTALL 右鍵, J, B
  5. install資料夾指令移動到C曹
  6. 指令配置bin環境變數
cmake -G “Visual Studio 15 2017 Win64” -DOPENCV_EXTRA_MODULES_PATH=E:\Downloads\OpenCV\opencv_contrib\modules E:\Downloads\OpenCV\opencv
中間3-4不知道有沒有指令可以完成,剩下的都可以寫成批次檔自動完成。