SaleaeLogic16 邏輯儀分析波形
- 前言
- 一、串口波形分析
- (一)keil虛擬波形仿真
- (二)邏輯儀分析串口發送
- 二、I2C協議
- 三、SPI協議
- 總結
前言
本例是通過SaleaeLogic16邏輯儀觀察波形,對前幾篇實驗博客涉及的協議進行分析,旨在深刻的理解不同協議下的通訊方式的異同,
以下是涉及到的相關博客
UART協議:stm32之串口通信
I2C協議:AHT20溫濕度采集(I2C協議)
SPI協議:玩轉oled屏(基于SPI協議)
一、串口波形分析
本例使用到的是上一篇博客中的工程
基于C8T6核心板的ucOS檔案移植
(一)keil虛擬波形仿真
首先在對應工程下點擊新建檔案

將以下內容復制進去并保存到對應的MDK-ARM中去
map 0x40000000, 0x40007FFF read write // APB1
map 0x40010000, 0x400157FF read write // APB2
map 0x40020000, 0x4007FFFF read write // AHB1
map 0x50000000, 0x50060BFF read write // AHB2
map 0x60000000, 0x60000FFF read write // AHB3
map 0xE0000000, 0xE00FFFFF read write // CORTEX-M4 internal peripherals
其中檔案名后綴是.ini,保存型別一定要是All Files(*.*)型別

然后配置一些模擬仿真的引數

此外,還需要注意的一點是選擇仿真的時鐘頻率與所選芯片型號是否對應,我這里是C8T6,對應外部晶振頻率為8MHz

然后開始仿真,打開邏輯分析儀

設定需要顯示的通道

點擊全速運行,等待一段時間,觀察波形

等待一段時間后,波形如下

我們可以看到,串口USART1_SR通道每隔2s都會有一個下降沿,我們把其展開,得到了下面的圖形

這一整塊就是我們每隔2s定時發送的資料,只不過由于資料量太小,而波特率太高,所以在2s的周期里才會表現的像一個沖擊,
我們可計算以下發送這一資料所需要的時間
發送資料:hello uc/OS! 歡迎來到RTOS多任務環境!\r\n,總計約40個位元組
波特率為115200bps
所需時間為(40*8)/115200 ,約為2.8ms
我們在后面邏輯分析儀對其分析的時候,會具體分析資料是怎么通過串口被發出去的,
(二)邏輯儀分析串口發送
在分析串口之前,我們首先觀察以下串口的基本配置,這在下面的分析中也會用到
使用串口1、波特率為115200、停止位為1 bit、資料位為8 bit、無校驗位等
具體配置如下
void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}

我們在邏輯分析儀器中可以看到,以下是一連串的密密麻麻的波形,我們把其展開分析

- 計算大概的波特率

從邏輯分析儀中可以看到,傳輸一位資料大約需要8.7us
則1ms可傳輸約114.9425289個資料位
則1s的時間可傳輸114.9425289*1000≈114943bps
而理論速度應為115200bps
關于這部分的解釋,有可能是因為SaleaeLogic16 邏輯儀設定的采樣頻率較低,遭成的誤差
資料發送部分分析

對應字符的ASCII表

對比波形,可分析得到前兩個資料發送的分別是’‘h’’, ‘‘e’’,需要注意的是
串口傳輸資料時先傳送字符的低位,后傳送字符的高位,即低位(LSB)在前,高位(MSB)在后,
串口通訊中是一個字符一個字符地傳輸,每個字符一位一位地傳輸,并且傳輸一個字符時,總是以“起始位”開始,以“停止位”結束,字符之間沒有固定的時間間隔要求,停止位和空閑位都規定為高電平,
詳情可參考
MSB與LSB
如果小伙伴們耐心下來去分析,可以發現這一系列密密麻麻的波形發送的正是我們想要發送的資料,
static void send_msg (void *p_arg)
{
OS_ERR err;
(void)p_arg;
BSP_Init(); /* Initialize BSP functions */
CPU_Init();
Mem_Init(); /* Initialize Memory Management Module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
CPU_IntDisMeasMaxCurReset();
AppTaskCreate(); /* Create Application Tasks */
AppObjCreate(); /* Create Application Objects */
while (DEF_TRUE)
{
printf("hello uc/OS! 歡迎來到RTOS多任務環境!\r\n");
OSTimeDlyHMSM(0, 0, 2, 0,OS_OPT_TIME_HMSM_STRICT,&err);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
二、I2C協議
- main函式
int main(void)
{
delay_init(); //延時初始化
uart_init(115200); //串口初始化
IIC_Init();
while(1)
{
printf("溫度濕度顯示");
read_AHT20_once();
delay_ms(1500);
}
}
- read_AHT20_once函式
void read_AHT20_once(void)
{
delay_ms(10);
reset_AHT20();
delay_ms(10);
init_AHT20();
delay_ms(10);
startMeasure_AHT20();
delay_ms(80);
read_AHT20();
delay_ms(5);
}

- AHT20復位
void reset_AHT20(void)
{
I2C_Start();
I2C_WriteByte(0x70);
ack_status = Receive_ACK();
if(ack_status) printf("1");
else printf("1-n-");
I2C_WriteByte(0xBA);
ack_status = Receive_ACK();
if(ack_status) printf("2");
else printf("2-n-");
I2C_Stop();
/*
AHT20_OutData[0] = 0;
AHT20_OutData[1] = 0;
AHT20_OutData[2] = 0;
AHT20_OutData[3] = 0;
*/
}

- AHT20初始化
void init_AHT20(void)
{
I2C_Start();
I2C_WriteByte(0x70);
ack_status = Receive_ACK();
if(ack_status) printf("3");
else printf("3-n-");
I2C_WriteByte(0xE1);
ack_status = Receive_ACK();
if(ack_status) printf("4");
else printf("4-n-");
I2C_WriteByte(0x08);
ack_status = Receive_ACK();
if(ack_status) printf("5");
else printf("5-n-");
I2C_WriteByte(0x00);
ack_status = Receive_ACK();
if(ack_status) printf("6");
else printf("6-n-");
I2C_Stop();
}

- 發送測量信號
void startMeasure_AHT20(void)
{
//------------
I2C_Start();
I2C_WriteByte(0x70);
ack_status = Receive_ACK();
if(ack_status) printf("7");
else printf("7-n-");
I2C_WriteByte(0xAC);
ack_status = Receive_ACK();
if(ack_status) printf("8");
else printf("8-n-");
I2C_WriteByte(0x33);
ack_status = Receive_ACK();
if(ack_status) printf("9");
else printf("9-n-");
I2C_WriteByte(0x00);
ack_status = Receive_ACK();
if(ack_status) printf("10");
else printf("10-n-");
I2C_Stop();
}

- 讀取資料
void read_AHT20(void)
{
uint8_t i;
for(i=0; i<6; i++)
{
readByte[i]=0;
}
//-------------
I2C_Start();
I2C_WriteByte(0x71);
ack_status = Receive_ACK();
readByte[0]= I2C_ReadByte();
Send_ACK();
readByte[1]= I2C_ReadByte();
Send_ACK();
readByte[2]= I2C_ReadByte();
Send_ACK();
readByte[3]= I2C_ReadByte();
Send_ACK();
readByte[4]= I2C_ReadByte();
Send_ACK();
readByte[5]= I2C_ReadByte();
SendNot_Ack();
//Send_ACK();
I2C_Stop();
//--------------
if( (readByte[0] & 0x68) == 0x08 )
{
H1 = readByte[1];
H1 = (H1<<8) | readByte[2];
H1 = (H1<<8) | readByte[3];
H1 = H1>>4;
H1 = (H1*1000)/1024/1024;
T1 = readByte[3];
T1 = T1 & 0x0000000F;
T1 = (T1<<8) | readByte[4];
T1 = (T1<<8) | readByte[5];
T1 = (T1*2000)/1024/1024 - 500;
AHT20_OutData[0] = (H1>>8) & 0x000000FF;
AHT20_OutData[1] = H1 & 0x000000FF;
AHT20_OutData[2] = (T1>>8) & 0x000000FF;
AHT20_OutData[3] = T1 & 0x000000FF;
}
else
{
AHT20_OutData[0] = 0xFF;
AHT20_OutData[1] = 0xFF;
AHT20_OutData[2] = 0xFF;
AHT20_OutData[3] = 0xFF;
printf("lyy");
}
printf("\r\n");
printf("溫度:%d%d.%d",T1/100,(T1/10)%10,T1%10);
printf("濕度:%d%d.%d",H1/100,(H1/10)%10,H1%10);
printf("\r\n");
}

小結
本例我在使用SaleaeLogic16 邏輯儀分析波形時,最小系統板并沒有接AHT20傳感器,所以在用邏輯儀分析波形時,觀察得到的波形都是否定應答,與實際有一定出入;但是通過觀察波形,分析起始、停止位、資料位等,可以更細致的了解I2C協議,
三、SPI協議
| 通道 | 引腳 |
|---|---|
| Channel 0 | 片選控制信號 |
| Channel 1 | 資料/命令選擇控制信號 |
| Channel 2 | SPI時鐘信號 |
| Channel 3 | SPI資料信號 |
-
發送命令信號

-
發送資料信號

總結
關于這幾種常用的協議,我在這里只是作了一個最簡單的分析,由于編者能力有限,如有問題,望大家不吝指教!!!
關于本次分析所涉及到的工程與檔案,我放到了這里提取碼:negw,有需要自取
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/376020.html
標籤:其他
