目錄
前言:
IIC協(xié)議簡介:
1、起始信號和停止信號:
2、應(yīng)答信號:
3、讀寫字節(jié):
AT24C02:
字節(jié)寫操作:
頁寫操作:
讀操作:
MCP4017:
寫操作:
讀操作:
前言:
? ? ? ? 本篇文章主要介紹IIC通信協(xié)議,同時給大家介紹一下藍(lán)橋杯嵌入式的模塊的AT24C02和MCP4017,此外本篇博客會采用按鍵控制PB14來讀取可編程電阻MCP分的電壓值,并將電壓值存儲在AT24C02中。
IIC協(xié)議簡介:
????????I2C(IIC,Inter-Integrated Circuit), 一種半雙工通信協(xié)議,采用兩線式串行總線, 它是由數(shù)據(jù)線SDA和時鐘SCL構(gòu)成的串行總線,可發(fā)送和接收數(shù)據(jù),這兩條線必須通過上拉電阻連接正電源。數(shù)據(jù)傳輸只能在總線不忙時啟動。在CPU與被控IC之間、IC與IC之間進(jìn)行雙向傳送,高速IIC總線一般可達(dá)400kbps以上。
? ? ? ? 對于STM32來說,G4系列的芯片自帶3個硬件IIC,而對于我們的比賽來說,官方為我們提供的代碼采用的不是硬件上的IIC,而是使用PB6 和 PB7這兩個IO口來模擬IIC的進(jìn)程。接下來我會結(jié)合藍(lán)橋杯嵌入式為大家提供的參考代碼來為大家講解一下IIC通信的一些操作。
1、起始信號和停止信號:
? ? ? ? 下圖是IIC起始和停止時序圖,起始和停止均由主機(jī)來發(fā)出,IIC總線在主機(jī)發(fā)出起始信號后處于忙碌狀態(tài),而在主機(jī)發(fā)出停止信號后,總線處于空閑狀態(tài)(I2C總線總線的SDA和SCL兩條信號線同時處于高電平時,規(guī)定為總線的空閑狀態(tài)此時各個器件的輸出級場效應(yīng)管均處在截止?fàn)顟B(tài),即釋放總線,由兩條信號線各自的上拉電阻把電平拉高)。
????????
? ? ? ? 起始條件:在SCL保持為高電平的情況下,SDA出現(xiàn)一個下降沿,對應(yīng)代碼部分為:
void I2CStart(void)
{
SDA_Output(1);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SDA_Output(0);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME);
}
? ? ? ? 停止條件:在SCL保持為高電平的情況下,SDA出現(xiàn)一個上升沿,對應(yīng)代碼部分為:
void I2CStop(void)
{
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output(0);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SDA_Output(1);
delay1(DELAY_TIME);
}
2、應(yīng)答信號:
????????每當(dāng)主機(jī)向從機(jī)發(fā)送完一個字節(jié)的數(shù)據(jù),主機(jī)總是需要等待從機(jī)發(fā)出一個應(yīng)答信號,以檢驗(yàn)從機(jī)是否成功接收到了數(shù)據(jù)。
? ? ? ? 下面就是應(yīng)答時序圖,只有在DATA OUT 被置為低的時候,才會被認(rèn)為是從機(jī)產(chǎn)生應(yīng)答,否則被認(rèn)為是不應(yīng)答。
?????????等待從機(jī)發(fā)送應(yīng)答對應(yīng)代碼部分:
unsigned char I2CWaitAck(void)
{
unsigned short cErrTime = 5;
SDA_Input_Mode();
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
while(SDA_Input())
{
cErrTime--;
delay1(DELAY_TIME);
if (0 == cErrTime)
{
SDA_Output_Mode();
I2CStop();
return ERROR;
}
}
SDA_Output_Mode();
SCL_Output(0);
delay1(DELAY_TIME);
return SUCCESS;
}
? ? ? ? 主從機(jī)發(fā)送應(yīng)答或者非應(yīng)答對應(yīng)代碼:
/**
* @brief I2C發(fā)送確認(rèn)信號
* @param None
* @retval None
*/
void I2CSendAck(void)
{
SDA_Output(0);
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME);
}
/**
* @brief I2C發(fā)送非確認(rèn)信號
* @param None
* @retval None
*/
void I2CSendNotAck(void)
{
SDA_Output(1);
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME);
}
3、讀寫字節(jié):
? ? ? ? 在介紹讀寫字節(jié)前,我要給大家強(qiáng)調(diào)一點(diǎn),數(shù)據(jù)傳輸過程中,數(shù)據(jù)傳輸保持穩(wěn)定(在SCL高電平期間,SDA一直保持穩(wěn)定,沒有跳變),只有當(dāng)SCL被拉低后,SDA才能被改變在SCL為高電平期間(有效數(shù)據(jù)時間段),發(fā)送數(shù)據(jù),發(fā)送8次數(shù)據(jù),如果數(shù)據(jù)為1,顯然SDA是被拉高;如果數(shù)據(jù)為0,那么SDA被拉低
? ? ? ? ?對于IIC協(xié)議來說,傳輸?shù)絊DA上的數(shù)據(jù)必須是八位,在數(shù)據(jù)傳輸?shù)臅r候,先傳輸數(shù)據(jù)的最高位,再傳輸數(shù)據(jù)的最低位,也就是嵌入式工程師所說的高位先行(MSB),每當(dāng)有一個字節(jié)的數(shù)據(jù)發(fā)送后,必須發(fā)送一位應(yīng)答位,總的數(shù)據(jù)就是8位數(shù)據(jù)加1位應(yīng)答,也就是說一幀有9位數(shù)據(jù)。
? ? ? ? ?讀寫操作對應(yīng)的代碼部分:
/**
* @brief I2C發(fā)送一個字節(jié)
* @param cSendByte 需要發(fā)送的字節(jié)
* @retval None
*/
void I2CSendByte(unsigned char cSendByte)
{
unsigned char i = 8;
while (i--)
{
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output(cSendByte & 0x80);
delay1(DELAY_TIME);
cSendByte += cSendByte;
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
}
SCL_Output(0);
delay1(DELAY_TIME);
}
/**
* @brief I2C接收一個字節(jié)
* @param None
* @retval 接收到的字節(jié)
*/
unsigned char I2CReceiveByte(void)
{
unsigned char i = 8;
unsigned char cR_Byte = 0;
SDA_Input_Mode();
while (i--)
{
cR_Byte += cR_Byte;
SCL_Output(0);
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
cR_Byte |= SDA_Input();
}
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output_Mode();
return cR_Byte;
}
? ? ? ? 這里我要給大家解釋一點(diǎn)代碼,SDA_Output(cSendByte & 0x80);
? ? ? ? 函數(shù)每次接收過來的都是一個字節(jié),而通過&0x80就會保留最高位的數(shù)據(jù),舍棄后七位的數(shù)據(jù),也就是說,通過這個操作之后,就只有1位數(shù)據(jù)被保存了下來,然后通過cSendByte += cSendByte;將這一位數(shù)據(jù)進(jìn)行加法計(jì)算,這可以看作是這一位數(shù)據(jù)的左移運(yùn)算。同樣的道理也適用于cR_Byte += cR_Byte;cR_Byte |= ?SDA_Input();這兩句代碼。
AT24C02:
? ? ? ? AT24C02是一款2K容量的串行電可擦除只讀存儲器,內(nèi)部包含256個字節(jié),每個字節(jié)8位。
? ? ? ? ?在官方給出的原理圖上,AT24C02和MCP4017被掛載在了PB6 PB7兩個接口上,也就以為著,AT24C02是做為從機(jī)來跟單片機(jī)進(jìn)行通信的。這就要求我們?nèi)タ匆幌聰?shù)據(jù)手冊,找到其從機(jī)地址。
? ? ? ? ?手冊中的地址前4位是固定不變的,后3位是可以根據(jù)電平的高低來決定,最后一位由開發(fā)者決定是對其進(jìn)行讀操作還是寫操作來決定最后一位的數(shù)據(jù)是0還是1。而開發(fā)板將A2 A1 A0全部接地,這就決定了我們?nèi)绻米x操作就是0xA1,寫操作就是0xA0;
字節(jié)寫操作:
????????
?????????字節(jié)寫操作需要由單片機(jī)發(fā)出起始狀態(tài)和器件地址,緊跟著給出一個8位數(shù)據(jù)地址。一經(jīng)收到該地址,AT24C02就立刻發(fā)送應(yīng)答,并隨時鐘輸入8位數(shù)據(jù)。在收到8位數(shù)據(jù)之后,AT24C02再次發(fā)送應(yīng)答,單片機(jī)發(fā)送停止信號來終止寫操作。同時,這里要注意的是AT24C02每次寫完內(nèi)容后會自動指向下一個內(nèi)存空間。但是這里一定要延時一下,這樣才能保證寫入的正確
? ? ? ? AT24C02寫操作對應(yīng)代碼部分:
void EEPROM_write(unsigned char address,unsigned char data)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CSendByte(data);
I2CWaitAck();
I2CStop();//停止IIC
HAL_Delay(5);
}
頁寫操作:
????????
?????????AT24C02能進(jìn)行8字節(jié)頁面寫入,04、08和16系列設(shè)備能進(jìn)行16字節(jié)頁面寫入。激發(fā)寫頁面與激發(fā)寫字節(jié)相同,只是數(shù)據(jù)傳送設(shè)備無須在第一個字節(jié)隨時鐘輸入之后,發(fā)出一個停止?fàn)顟B(tài)。在EEPROM確認(rèn)收到第一個數(shù)據(jù)之后,數(shù)據(jù)傳送設(shè)備能再傳送7個(1KB、2KB)或15個(4KB、8KB、16KB)數(shù)據(jù),每一個數(shù)據(jù)收到之后,EEPROM都將通過SDA回送一個確認(rèn)信號,最后數(shù)據(jù)傳送設(shè)備必須通過停止?fàn)顟B(tài)終止頁面寫序列。
? ? ? ? 頁寫操作對應(yīng)代碼部分:
void EEPROM_pagewrite(unsigned char *pageBuf,unsigned char address,unsigned char num)
{
?? ?I2CStart();
?? ?I2CSendByte(0xa0); // 器件地址
?? ?I2CWaitAck();
?? ?
?? ?I2CSendByte(address); ?// 寫數(shù)據(jù)地址
?? ?I2CWaitAck();
?? ?
?? ?while(num--)
?? ?{
?? ??? ?I2CSendByte(*pageBuf++);
?? ??? ?I2CWaitAck();
?? ?}
?? ?I2CStop();
?? ?delay1(500);
}
讀操作:
? ? ? ? 讀取操作分為三種,分別是當(dāng)前地址讀取,一個是隨機(jī)讀取,另一個是順序讀取。這里給大家介紹一下隨機(jī)讀取,隨機(jī)讀取的時序圖如下所示。
? ? ? ? ?先由主機(jī)發(fā)送一個起始信號,緊接著再發(fā)送器件地址(0xa0),等待從機(jī)響應(yīng),然后發(fā)送讀取的地址,等待從機(jī)響應(yīng),之后再次發(fā)送起始信號,這時候發(fā)送的器件地址就是0xa1了,等待從機(jī)回應(yīng)之后,然后才開始數(shù)據(jù)讀取,每次進(jìn)行數(shù)據(jù)讀取后,需要進(jìn)行等待響應(yīng)操作,如果收到的響應(yīng)是不響應(yīng),那么這時候發(fā)送停止信號,代表著讀取結(jié)束。
unsigned char EEPROM_read(unsigned char address)
{
unsigned char dat;
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(address);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
dat = I2CReceiveByte();
I2CWaitAck();
I2CStop();
return dat;
}
MCP4017:
? ? ? ? MCP4017是一款可編程的電阻,其內(nèi)置了7位寄存器,共計(jì)127個檔位的分辨率。在藍(lán)橋杯嵌入式比賽中,MCP4017同樣放在了PB6 PB7 兩個IO上,我們可以用IIC總線來跟他通信。
? ? ? ? ?對于藍(lán)橋杯嵌入式比賽來說,采用的是MCP4017T-104ELT,也就是說他的最大電阻達(dá)到了100K。
? ? ? ? ?通過這張圖,我們可以清晰的看出,隨著我們向MCP中輸入的數(shù)越大,他對應(yīng)的電阻也就越大,當(dāng)我們傳入0x7f時,對應(yīng)的電阻就是100K。這里要注意的一點(diǎn)是,我們寫進(jìn)去的一個數(shù)字(0-127),讀出來也是一個數(shù)字,轉(zhuǎn)化為電阻阻值:R = 787.4 * read_resistor 歐,電壓:3.3*(R/(R+10)) (假設(shè)外接的電壓為3.3)
? ? ? ? ?通過閱讀數(shù)據(jù)手冊,我們可以得到MCP4017的從機(jī)地址,如果是讀操作的話就是0x5f,寫操作的話就是0X5E。接下來,我們根據(jù)時序圖來編寫MCP的讀寫操作。
寫操作:
????????
? ? ? ? ?這個就比AT24C02好看多了,先發(fā)送起始信號,等待響應(yīng),發(fā)送數(shù)據(jù),等待響應(yīng),結(jié)束信號,一個寫操作就結(jié)束了。對應(yīng)代碼部分如下:
void MCP4017_write(unsigned char value)
{
I2CStart();
I2CSendByte(0x5e);
I2CWaitAck();
I2CSendByte(value);
I2CWaitAck();
I2CStop();
}
讀操作:
????????
? ? ? ? ?這里需要注意的一點(diǎn)是主設(shè)備負(fù)責(zé)發(fā)起響應(yīng)和響應(yīng)信號。如果出現(xiàn)響應(yīng)信號,MCP4017將中止此傳輸并釋放總線。
? ? ? ? 讀取操作對應(yīng)的代碼部分:
unsigned char MCP4017_read(void)
{
unsigned char value;
I2CStart();
I2CSendByte(0x5f);
I2CWaitAck();
value = I2CReceiveByte();
I2CSendNotAck();
I2CStop();
return value;
}
按鍵控制PB14讀取可編程電阻MCP分得電壓,并將電壓值存儲在AT24C02中:
????????寫好的按鍵工程????????????????????????????????????????????????????????????????????????????????提取碼:2471
? ? ? ? 大家可以在我這個按鍵工程的基礎(chǔ)上進(jìn)行修改。
? ? ? ? 通過開發(fā)板上的B2 B3 B4個按鍵,來分別控制MCP4017不同的電阻值,同時利用B1來顯示上一次存儲到AT24C02中的電壓。
????????1、將PB6 PB7設(shè)定為推挽輸出
2、設(shè)定PB14為ADC通道,并完成相關(guān)配置
?
Resolution:ADC采樣的分辨率這里直接默認(rèn)選擇12位的精度就可以了,如輸入電壓為0-3.3V,12位,即0V對應(yīng)0,3.3V對應(yīng)2^12-1=4095,通過這個轉(zhuǎn)換我們就可以算出對應(yīng)的電壓值。
Rank:采樣間隔設(shè)置我們這里選擇默認(rèn)2.5就行了,間隔越小采樣頻率越高。?之后,咱們的Cubemx的配置就算基本完成了,點(diǎn)擊generate生成代碼即可。不過要記得把官方提供的i2c_hal.c和i2c_hal.h加入我們的工程。
? ? ? ? 打開工程后,在i2c_hal.c里面添加AT24C02和MCP4017的代碼,并且在.h文件中聲明一下文章來源:http://www.zghlxwxcb.cn/news/detail-406086.html
AD采集對應(yīng)的代碼:
unsigned int adc_val;
float vol;
void Get_vol()
{
HAL_ADC_Start(&hadc1);
adc_val = HAL_ADC_GetValue(&hadc1);
vol = adc_val/4096.0f * 3.3f;
}
主函數(shù)對應(yīng)的代碼:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2022 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#include "lcd.h"
//#include "fonts.h"
#include "interrupt.h"
#include "stdio.h"
#include "i2c_hal.h"
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
char text[20];
extern unsigned int TIM3_count;
extern struct keys key[4];
unsigned char TIM3_count_H;
unsigned char TIM3_count_L;
unsigned int EEPROM_temp;
unsigned char res_4017;
unsigned int PB14_ADC;
float volt1;
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM3_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1);
PB14_ADC = HAL_ADC_GetValue(&hadc1);
volt1 = PB14_ADC * 3.5/4096;
sprintf(text,"Now time_value:%d",TIM3_count);
LCD_DisplayStringLine(Line4 ,(unsigned char *)text);
EEPROM_temp = (EEPROM_read(0x00)<<8)+EEPROM_read(0x01);
sprintf(text,"EEPROM_temp:%d",EEPROM_temp);
LCD_DisplayStringLine(Line1 ,(unsigned char *)text);
sprintf(text,"RES %5.4fK",res_4017*0.7874);
LCD_DisplayStringLine(Line6,(uint8_t *)text);
sprintf(text,"Vol %5.4fV",3.3*res_4017*0.7874/(res_4017*0.7874 + 10));
LCD_DisplayStringLine(Line3, (unsigned char *)text);
sprintf(text,"ture %5.4fV",volt1);
// sprintf(text,"ture %d",PB14_ADC);
LCD_DisplayStringLine(Line7, (unsigned char *)text);
if(key[0].single_flag == 1)
{
sprintf(text,"key0down");
LCD_DisplayStringLine(Line8,(uint8_t *)text);
MCP4017_write(0x00);
res_4017 = MCP4017_read();
key[0].single_flag = 0;
}
else if(key[1].single_flag == 1)
{
sprintf(text,"key1down");
LCD_DisplayStringLine(Line8,(uint8_t *)text);
MCP4017_write(0x0d);
res_4017 = MCP4017_read();
key[1].single_flag = 0;
}
else if(key[2].single_flag == 1)
{
sprintf(text,"key2down");
LCD_DisplayStringLine(Line8,(uint8_t *)text);
key[2].single_flag = 0;
MCP4017_write(0x40);
res_4017 = MCP4017_read();
}
else if(key[3].single_flag == 1)
{
TIM3_count_H = TIM3_count >> 8;
TIM3_count_L = TIM3_count & 0xff;
EEPROM_write(0x00,TIM3_count_H);
HAL_Delay(10); //寫入需要時間,延時是為了給寫操作留出時間
EEPROM_write(0x01,TIM3_count_L);
HAL_Delay(10);
sprintf(text,"key3down");
MCP4017_write(0x7f);
res_4017 = MCP4017_read();
LCD_DisplayStringLine(Line8,(uint8_t *)text);
key[3].single_flag = 0;
}
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
RCC_OscInitStruct.PLL.PLLN = 20;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
/** Initializes the peripherals clocks
*/
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC12;
PeriphClkInit.Adc12ClockSelection = RCC_ADC12CLKSOURCE_SYSCLK;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
最終代碼實(shí)現(xiàn):
最終代碼? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 提取碼:2471文章來源地址http://www.zghlxwxcb.cn/news/detail-406086.html
到了這里,關(guān)于藍(lán)橋杯嵌入式(G4系列)HAL:IIC通信之AT24C02與MCP4017的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!