新增驱动文件

This commit is contained in:
许晟昊 2025-04-28 11:23:13 +08:00
commit a6cb7e50f8
32 changed files with 5637 additions and 0 deletions

18
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "windows-gcc-x64",
"includePath": [
"${workspaceFolder}/**"
],
"compilerPath": "C:/TDM-GCC-64/bin/gcc.exe",
"cStandard": "${default}",
"cppStandard": "${default}",
"intelliSenseMode": "windows-gcc-x64",
"compilerArgs": [
""
]
}
],
"version": 4
}

24
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,24 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "C/C++ Runner: Debug Session",
"type": "cppdbg",
"request": "launch",
"args": [],
"stopAtEntry": false,
"externalConsole": true,
"cwd": "e:/work/stm32/driver/DAC",
"program": "e:/work/stm32/driver/DAC/build/Debug/outDebug",
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}

59
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,59 @@
{
"C_Cpp_Runner.cCompilerPath": "gcc",
"C_Cpp_Runner.cppCompilerPath": "g++",
"C_Cpp_Runner.debuggerPath": "gdb",
"C_Cpp_Runner.cStandard": "",
"C_Cpp_Runner.cppStandard": "",
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Auxiliary/Build/vcvarsall.bat",
"C_Cpp_Runner.useMsvc": false,
"C_Cpp_Runner.warnings": [
"-Wall",
"-Wextra",
"-Wpedantic",
"-Wshadow",
"-Wformat=2",
"-Wcast-align",
"-Wconversion",
"-Wsign-conversion",
"-Wnull-dereference"
],
"C_Cpp_Runner.msvcWarnings": [
"/W4",
"/permissive-",
"/w14242",
"/w14287",
"/w14296",
"/w14311",
"/w14826",
"/w44062",
"/w44242",
"/w14905",
"/w14906",
"/w14263",
"/w44265",
"/w14928"
],
"C_Cpp_Runner.enableWarnings": true,
"C_Cpp_Runner.warningsAsError": false,
"C_Cpp_Runner.compilerArgs": [],
"C_Cpp_Runner.linkerArgs": [],
"C_Cpp_Runner.includePaths": [],
"C_Cpp_Runner.includeSearch": [
"*",
"**/*"
],
"C_Cpp_Runner.excludeSearch": [
"**/build",
"**/build/**",
"**/.*",
"**/.*/**",
"**/.vscode",
"**/.vscode/**"
],
"C_Cpp_Runner.useAddressSanitizer": false,
"C_Cpp_Runner.useUndefinedSanitizer": false,
"C_Cpp_Runner.useLeakSanitizer": false,
"C_Cpp_Runner.showCompilationTime": false,
"C_Cpp_Runner.useLinkTimeOptimization": false,
"C_Cpp_Runner.msvcSecureNoWarnings": false
}

455
ADC/ad7124.c Normal file
View File

@ -0,0 +1,455 @@
#include "ad7124.h"
/* Error codes */
#define INVALID_VAL -1 /* Invalid argument */
#define COMM_ERR -2 /* Communication error on receive */
#define AD7124_TIMEOUT -3 /* A timeout has occured */
// 配置ad7124寄存器的值根据实际项目需求配置
static ad7124_st_reg_t ad7124_regs[AD7124_REG_NO] = {
{AD7124_STATUS, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Status */
{AD7124_ADC_CONTROL, 0x0280, AD7124_SIZE_2, AD7124_RW}, /* AD7124_ADC_Control */
{AD7124_DATA, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Data */
{AD7124_IOCON1, 0x000000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_IOCon1 */
{AD7124_IOCON2, 0x0000, AD7124_SIZE_2, AD7124_RW}, /* AD7124_IOCon2 */
{AD7124_ID, 0x02, AD7124_SIZE_1, AD7124_R}, /* AD7124_ID */
{AD7124_ERROR, 0x000000, AD7124_SIZE_3, AD7124_R}, /* AD7124_Error */
{AD7124_ERROR_EN, 0x000040, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Error_En */
{AD7124_MCLK_COUNT, 0x00, AD7124_SIZE_1, AD7124_R}, /* AD7124_Mclk_Count */
{AD7124_CHANNEL_0, 0x0051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
{AD7124_CHANNEL_1, 0x0071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
{AD7124_CHANNEL_2, 0x0091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
{AD7124_CHANNEL_3, 0x00B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
{AD7124_CHANNEL_4, 0x00D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
{AD7124_CHANNEL_5, 0x00F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
{AD7124_CHANNEL_6, 0x0111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
{AD7124_CHANNEL_7, 0x0131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
{AD7124_CHANNEL_8, 0x0151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
{AD7124_CHANNEL_9, 0x0171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
{AD7124_CHANNEL_10, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_10 */
{AD7124_CHANNEL_11, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_11 */
{AD7124_CHANNEL_12, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_12 */
{AD7124_CHANNEL_13, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_13 */
{AD7124_CHANNEL_14, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_14 */
{AD7124_CHANNEL_15, 0x0001, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_15 */
{AD7124_CONFIG_0, 0x01E0, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_0 */
{AD7124_CONFIG_1, 0x0040, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_1 */
{AD7124_CONFIG_2, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_2 */
{AD7124_CONFIG_3, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_3 */
{AD7124_CONFIG_4, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_4 */
{AD7124_CONFIG_5, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_5 */
{AD7124_CONFIG_6, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_6 */
{AD7124_CONFIG_7, 0x0860, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Config_7 */
{AD7124_FILTER_0, 0x060020, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_0 */
{AD7124_FILTER_1, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_1 */
{AD7124_FILTER_2, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_2 */
{AD7124_FILTER_3, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_3 */
{AD7124_FILTER_4, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_4 */
{AD7124_FILTER_5, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_5 */
{AD7124_FILTER_6, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_6 */
{AD7124_FILTER_7, 0x060180, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Filter_7 */
{AD7124_OFFSET_0, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_0 */
{AD7124_OFFSET_1, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_1 */
{AD7124_OFFSET_2, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_2 */
{AD7124_OFFSET_3, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_3 */
{AD7124_OFFSET_4, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_4 */
{AD7124_OFFSET_5, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_5 */
{AD7124_OFFSET_6, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_6 */
{AD7124_OFFSET_7, 0x800000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Offset_7 */
{AD7124_GAIN_0, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_0 */
{AD7124_GAIN_1, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_1 */
{AD7124_GAIN_2, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_2 */
{AD7124_GAIN_3, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_3 */
{AD7124_GAIN_4, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_4 */
{AD7124_GAIN_5, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_5 */
{AD7124_GAIN_6, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_6 */
{AD7124_GAIN_7, 0x500000, AD7124_SIZE_3, AD7124_RW}, /* AD7124_Gain_7 */
};
static ad7124_st_reg_t ad7124_channel_regs[AD7124_CHANNEL_EN_MAX] = {
{AD7124_CHANNEL_0, 0x8051, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_0 */
{AD7124_CHANNEL_1, 0x8071, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_1 */
{AD7124_CHANNEL_2, 0x8091, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_2 */
{AD7124_CHANNEL_3, 0x80B1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_3 */
{AD7124_CHANNEL_4, 0x80D1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_4 */
{AD7124_CHANNEL_5, 0x80F1, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_5 */
{AD7124_CHANNEL_6, 0x8111, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_6 */
{AD7124_CHANNEL_7, 0x8131, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_7 */
{AD7124_CHANNEL_8, 0x8151, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_8 */
{AD7124_CHANNEL_9, 0x8171, AD7124_SIZE_2, AD7124_RW}, /* AD7124_Channel_9 */
};
ad7124_analog_t ad7124_analog[AD7124_CHANNEL_EN_MAX] = {NULL}; // AD通道采样结构体数组用于存放AD通道采样数据
/**
* @brief AD7124寄存器
*
* AD7124的寄存器值
*
* @param p_reg
*
* @return 0
*/
int32_t ad7124_no_check_read_register(ad7124_st_reg_t *p_reg)
{
int32_t ret = 0;
uint8_t buffer[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t i = 0;
uint8_t add_status_length = 0;
/* Build the Command word */
buffer[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_RD |
AD7124_COMM_REG_RA(p_reg->addr);
/*
* If this is an AD7124_DATA register read, and the DATA_STATUS bit is set
* in ADC_CONTROL, need to read 4, not 3 bytes for DATA with STATUS
*/
if ((p_reg->addr == AD7124_DATA) &&
(ad7124_regs[AD7124_ADC_CONTROL].value & AD7124_ADC_CTRL_REG_DATA_STATUS))
{
add_status_length = 1; // 此处是根据寄存器配置而决定,根据AD7124_ADC_CONTROL第10位决定
}
/* Read data from the device */
ret = ad7124_read_write_spi(buffer, p_reg->size + 1 + add_status_length);
if (ret < 0)
return ret;
/*
* if reading Data with 4 bytes, need to copy the status byte to the STATUS
* register struct value member
*/
if (add_status_length)
{
ad7124_regs[AD7124_STATUS].value = buffer[p_reg->size + 1];
}
/* Build the result */
p_reg->value = 0;
for (i = 1; i < p_reg->size + 1; i++)
{
p_reg->value <<= 8;
p_reg->value += buffer[i];
}
return ret;
}
/**
* @brief AD7124寄存器写入数据
*
* AD7124寄存器
*
* @param reg
* @return 0
*/
int32_t ad7124_no_check_write_register(ad7124_st_reg_t *reg)
{
int32_t ret = 0;
int32_t reg_value = 0;
uint8_t wr_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t i = 0;
/* Build the Command word */
wr_buf[0] = AD7124_COMM_REG_WEN | AD7124_COMM_REG_WR |
AD7124_COMM_REG_RA(reg->addr);
/* Fill the write buffer */
reg_value = reg->value;
for (i = 0; i < reg->size; i++)
{
wr_buf[reg->size - i] = reg_value & 0xFF;
reg_value >>= 8;
}
/* Write data to the device */
ret = ad7124_read_write_spi(wr_buf, reg->size + 1);
return ret;
}
/**
* @brief AD7124寄存器读取数据
*
* AD7124的指定寄存器中读取数据
*
* @param p_reg ad7124_st_reg_t类型的指针
*
* @return
*
* ERROR寄存器的SPI_IGNORE_ERR位
*/
int32_t ad7124_read_register(ad7124_st_reg_t *p_reg)
{
int32_t ret;
if (p_reg->addr != AD7124_ERROR && (ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
{
ret = ad7124_wait_for_spi_ready(AD7124_RDY); // 读寄存器之前检查ERROR寄存器的SPI_IGNORE_ERR位
if (ret < 0)
return ret;
}
ret = ad7124_no_check_read_register(p_reg);
return ret;
}
/**
* @brief AD7124寄存器写入数据
*
* AD7124的指定寄存器SPI错误的功能SPI接口准备就绪
*
* @param p_reg
*
* @return 0
*/
int32_t ad7124_write_register(ad7124_st_reg_t *p_reg)
{
int32_t ret;
if ((ad7124_regs[AD7124_ERROR_EN].value & AD7124_ERREN_REG_SPI_IGNORE_ERR_EN))
{
ret = ad7124_wait_for_spi_ready(AD7124_RDY);
if (ret < 0)
return ret;
}
ret = ad7124_no_check_write_register(p_reg);
return ret;
}
/**
* @brief AD7124设备
*
* SPI接口向AD7124发送重置命令
*
* @return 0
*/
int32_t ad7124_reset(void)
{
int32_t ret = 0;
uint8_t wr_buf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 发送64个1复位ad7124芯片
ret = ad7124_read_write_spi(wr_buf, 8);
/* Read POR bit to clear */
ret = ad7124_wait_to_power_on(AD7124_RDY);
return ret;
}
/**
* @brief SPI接口准备就绪
*
* AD7124的SPI接口准备就绪
*
* @param timeout
* @return 0AD7124_TIMEOUT
*/
int32_t ad7124_wait_for_spi_ready(uint32_t timeout)
{
int32_t ret;
int8_t ready = 0;
while (!ready && --timeout)
{
/* Read the value of the Error Register */
ret = ad7124_read_register(&ad7124_regs[AD7124_ERROR]);
if (ret < 0)
return ret;
/* Check the SPI IGNORE Error bit in the Error Register */
ready = (ad7124_regs[AD7124_ERROR].value &
AD7124_ERR_REG_SPI_IGNORE_ERR) == 0;
}
return timeout ? 0 : AD7124_TIMEOUT;
}
/**
* @brief AD7124电源开启
*
* AD7124设备电源开启
*
* @param timeout
*
* @return 0AD7124_TIMEOUT表示超时
*/
int32_t ad7124_wait_to_power_on(uint32_t timeout)
{
int32_t ret;
int8_t powered_on = 0;
while (!powered_on && timeout--)
{
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
if (ret < 0)
return ret;
/* Check the POR_FLAG bit in the Status Register */
powered_on = (ad7124_regs[AD7124_STATUS].value &
AD7124_STATUS_REG_POR_FLAG) == 0;
}
return (timeout || powered_on) ? 0 : AD7124_TIMEOUT;
}
/**
* @brief AD7124转换准备就绪
*
* AD7124完成转换并准备就绪
*
* @param timeout
* @return 0AD7124_TIMEOUT
*/
int32_t ad7124_wait_for_conv_ready(uint32_t timeout)
{
int32_t ret;
int8_t ready = 0;
while (!ready && --timeout)
{
/* Read the value of the Status Register */
ret = ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
if (ret < 0)
return ret;
/* Check the RDY bit in the Status Register */
ready = (ad7124_regs[AD7124_STATUS].value &
AD7124_STATUS_REG_RDY) == 0;
}
return timeout ? 0 : AD7124_TIMEOUT;
}
/**
* @brief AD7124读取数据
*
* AD7124的数据寄存器中读取数据值
*
* @return
*/
int32_t ad7124_read_data(void)
{
int32_t read_data;
/* Read the value of the Status Register */
ad7124_read_register(&ad7124_regs[AD7124_DATA]);
/* Get the read result */
read_data = ad7124_regs[AD7124_DATA].value;
return read_data;
}
/**
* @brief AD7124获取模拟信号数据
*
* SPI接口从AD7124芯片获取模拟信号数据ad7124_analog中
*
* @details
* -
* - AD7124完成转换
* -
* -
* -
*
* @note
* - ad7124_analog中
* - Code = (0xFFFFFF × AIN × Gain)/VREFVREF为参考电压GAIN为增益AD_CODE为AD代码
* - = / * 1000AD7124_RESmA
*/
// void ad7124_get_analog(void)
// {
// int32_t read_data;
// uint8_t i;
// uint8_t channel;
// // for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
// // {
// // ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[i].value;
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// // ad7124_read_register(&ad7124_regs[AD7124_STATUS]);
// while (ad7124_wait_for_conv_ready(AD7124_RDY))
// ; // 等待转换完成
// channel = ad7124_regs[AD7124_STATUS].value;
// ad7124_analog[channel].channel = channel;
// read_data = ad7124_read_data();
// ad7124_analog[channel].data = read_data;
// ad7124_analog[channel].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式Code = (0xFFFFFF × AIN × Gain)/VREF
// ad7124_analog[channel].current = (float)(ad7124_analog[channel].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
// // ad7124_regs[AD7124_CHANNEL_0].value = 0;
// // ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// // }
// }
void ad7124_get_analog(uint8_t channel_nr)
{
int32_t read_data;
// for (i = STOP_NC_ADC; i < AD7124_CHANNEL_EN_MAX; i++)
// {
ad7124_regs[AD7124_CHANNEL_0].value = ad7124_channel_regs[channel_nr].value;
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
while (ad7124_wait_for_conv_ready(AD7124_RDY))
; // 等待转换完成
ad7124_analog[channel_nr].channel = channel_nr;
read_data = ad7124_read_data();
ad7124_analog[channel_nr].data = read_data;
ad7124_analog[channel_nr].voltage = (float)(read_data * VREF / GAIN / AD_CODE); // AD7124单极性计算公式Code = (0xFFFFFF × AIN × Gain)/VREF
ad7124_analog[channel_nr].current = (float)(ad7124_analog[channel_nr].voltage / AD7124_RES * 1000); // 乘1000是为了将单位转换为mA
ad7124_regs[AD7124_CHANNEL_0].value = 0;
ad7124_write_register(&ad7124_regs[AD7124_CHANNEL_0]);
// }
}
/**
* @brief AD7124设备
*
* AD7124设备
*
* @return 0
*/
int32_t ad7124_setup(void)
{
int32_t ret;
uint8_t reg_nr;
// board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用并且时序不一样所以要先初始化SPI接口。
/* Reset the device interface.*/
ret = ad7124_reset();
if (ret < 0)
return ret;
HAL_Delay(10);
ad7124_read_register(&ad7124_regs[AD7124_ID]);
/* Initialize registers AD7124_ADC_Control through AD7124_Filter_7. */
for (reg_nr = AD7124_STATUS; reg_nr < AD7124_OFFSET_0; reg_nr++) // 对ad7124的可写寄存器进行配置不包括只读寄存器
{
// ret = ad7124_read_register(&ad7124_regs[reg_nr]);
if (ad7124_regs[reg_nr].rw == AD7124_RW)
{
ret = ad7124_write_register(&ad7124_regs[reg_nr]);
ret = ad7124_read_register(&ad7124_regs[reg_nr]);
if (ret < 0)
break;
}
}
HAL_GPIO_WritePin(AD7124_SYNC_GPIO_Port, AD7124_SYNC_Pin, GPIO_PIN_SET); // AD7124同步信号使能
return ret;
}
/**
* @brief SPI接口对AD7124进行读写操作
*
* SPI接口对AD7124进行读写操作
*
* @param buff
* @param length
*
* @return 0
*/
int32_t ad7124_read_write_spi(uint8_t *buff, uint8_t length)
{
int32_t ret;
board_spi_init(AD7124); // 初始化SPI,因为DAC161的SPI要和AD7124共用并且时序不一样所以要先初始化SPI接口。
board_spi_cs_on(AD7124);
ret = spi_transmit_receive(&hspi1, buff, length);
board_spi_cs_off(AD7124);
return ret;
}

309
ADC/ad7124.h Normal file
View File

@ -0,0 +1,309 @@
#ifndef __AD7124_H
#define __AD7124_H
/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "main.h"
#include "user_spi.h"
/******************************************************************************/
/******************* Register map and register definitions ********************/
/******************************************************************************/
/* Communication Register bits */
#define AD7124_COMM_REG_WEN (0 << 7)
#define AD7124_COMM_REG_WR (0 << 6)
#define AD7124_COMM_REG_RD (1 << 6)
#define AD7124_COMM_REG_RA(x) ((x) & 0x3F)
/* Status Register bits */
#define AD7124_STATUS_REG_RDY (1 << 7)
#define AD7124_STATUS_REG_ERROR_FLAG (1 << 6)
#define AD7124_STATUS_REG_POR_FLAG (1 << 4)
#define AD7124_STATUS_REG_CH_ACTIVE(x) ((x) & 0xF)
/* ADC_Control Register bits */
#define AD7124_ADC_CTRL_REG_DOUT_RDY_DEL (1 << 12)
#define AD7124_ADC_CTRL_REG_CONT_READ (1 << 11)
#define AD7124_ADC_CTRL_REG_DATA_STATUS (1 << 10)
#define AD7124_ADC_CTRL_REG_CS_EN (1 << 9)
#define AD7124_ADC_CTRL_REG_REF_EN (1 << 8)
#define AD7124_ADC_CTRL_REG_POWER_MODE(x) (((x) & 0x3) << 6)
#define AD7124_ADC_CTRL_REG_MODE(x) (((x) & 0xF) << 2)
#define AD7124_ADC_CTRL_REG_CLK_SEL(x) (((x) & 0x3) << 0)
/* IO_Control_1 Register bits */
#define AD7124_IO_CTRL1_REG_GPIO_DAT2 (1 << 23)
#define AD7124_IO_CTRL1_REG_GPIO_DAT1 (1 << 22)
#define AD7124_IO_CTRL1_REG_GPIO_CTRL2 (1 << 19)
#define AD7124_IO_CTRL1_REG_GPIO_CTRL1 (1 << 18)
#define AD7124_IO_CTRL1_REG_PDSW (1 << 15)
#define AD7124_IO_CTRL1_REG_IOUT1(x) (((x) & 0x7) << 11)
#define AD7124_IO_CTRL1_REG_IOUT0(x) (((x) & 0x7) << 8)
#define AD7124_IO_CTRL1_REG_IOUT_CH1(x) (((x) & 0xF) << 4)
#define AD7124_IO_CTRL1_REG_IOUT_CH0(x) (((x) & 0xF) << 0)
/* IO_Control_1 AD7124-8 specific bits */
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT4 (1 << 23)
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT3 (1 << 22)
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT2 (1 << 21)
#define AD7124_8_IO_CTRL1_REG_GPIO_DAT1 (1 << 20)
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL4 (1 << 19)
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL3 (1 << 18)
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL2 (1 << 17)
#define AD7124_8_IO_CTRL1_REG_GPIO_CTRL1 (1 << 16)
/* IO_Control_2 Register bits */
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS7 (1 << 15)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS6 (1 << 14)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS5 (1 << 11)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS4 (1 << 10)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS3 (1 << 5)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS2 (1 << 4)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS1 (1 << 1)
#define AD7124_IO_CTRL2_REG_GPIO_VBIAS0 (1 << 0)
/* IO_Control_2 AD7124-8 specific bits */
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS15 (1 << 15)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS14 (1 << 14)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS13 (1 << 13)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS12 (1 << 12)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS11 (1 << 11)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS10 (1 << 10)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS9 (1 << 9)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS8 (1 << 8)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS7 (1 << 7)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS6 (1 << 6)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS5 (1 << 5)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS4 (1 << 4)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS3 (1 << 3)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS2 (1 << 2)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS1 (1 << 1)
#define AD7124_8_IO_CTRL2_REG_GPIO_VBIAS0 (1 << 0)
/* ID Register bits */
#define AD7124_ID_REG_DEVICE_ID(x) (((x) & 0xF) << 4)
#define AD7124_ID_REG_SILICON_REV(x) (((x) & 0xF) << 0)
/* Error Register bits */
#define AD7124_ERR_REG_LDO_CAP_ERR (1 << 19)
#define AD7124_ERR_REG_ADC_CAL_ERR (1 << 18)
#define AD7124_ERR_REG_ADC_CONV_ERR (1 << 17)
#define AD7124_ERR_REG_ADC_SAT_ERR (1 << 16)
#define AD7124_ERR_REG_AINP_OV_ERR (1 << 15)
#define AD7124_ERR_REG_AINP_UV_ERR (1 << 14)
#define AD7124_ERR_REG_AINM_OV_ERR (1 << 13)
#define AD7124_ERR_REG_AINM_UV_ERR (1 << 12)
#define AD7124_ERR_REG_REF_DET_ERR (1 << 11)
#define AD7124_ERR_REG_DLDO_PSM_ERR (1 << 9)
#define AD7124_ERR_REG_ALDO_PSM_ERR (1 << 7)
#define AD7124_ERR_REG_SPI_IGNORE_ERR (1 << 6)
#define AD7124_ERR_REG_SPI_SLCK_CNT_ERR (1 << 5)
#define AD7124_ERR_REG_SPI_READ_ERR (1 << 4)
#define AD7124_ERR_REG_SPI_WRITE_ERR (1 << 3)
#define AD7124_ERR_REG_SPI_CRC_ERR (1 << 2)
#define AD7124_ERR_REG_MM_CRC_ERR (1 << 1)
#define AD7124_ERR_REG_ROM_CRC_ERR (1 << 0)
/* Error_En Register bits */
#define AD7124_ERREN_REG_MCLK_CNT_EN (1 << 22)
#define AD7124_ERREN_REG_LDO_CAP_CHK_TEST_EN (1 << 21)
#define AD7124_ERREN_REG_LDO_CAP_CHK(x) (((x) & 0x3) << 19)
#define AD7124_ERREN_REG_ADC_CAL_ERR_EN (1 << 18)
#define AD7124_ERREN_REG_ADC_CONV_ERR_EN (1 << 17)
#define AD7124_ERREN_REG_ADC_SAT_ERR_EN (1 << 16)
#define AD7124_ERREN_REG_AINP_OV_ERR_EN (1 << 15)
#define AD7124_ERREN_REG_AINP_UV_ERR_EN (1 << 14)
#define AD7124_ERREN_REG_AINM_OV_ERR_EN (1 << 13)
#define AD7124_ERREN_REG_AINM_UV_ERR_EN (1 << 12)
#define AD7124_ERREN_REG_REF_DET_ERR_EN (1 << 11)
#define AD7124_ERREN_REG_DLDO_PSM_TRIP_TEST_EN (1 << 10)
#define AD7124_ERREN_REG_DLDO_PSM_ERR_ERR (1 << 9)
#define AD7124_ERREN_REG_ALDO_PSM_TRIP_TEST_EN (1 << 8)
#define AD7124_ERREN_REG_ALDO_PSM_ERR_EN (1 << 7)
#define AD7124_ERREN_REG_SPI_IGNORE_ERR_EN (1 << 6)
#define AD7124_ERREN_REG_SPI_SCLK_CNT_ERR_EN (1 << 5)
#define AD7124_ERREN_REG_SPI_READ_ERR_EN (1 << 4)
#define AD7124_ERREN_REG_SPI_WRITE_ERR_EN (1 << 3)
#define AD7124_ERREN_REG_SPI_CRC_ERR_EN (1 << 2)
#define AD7124_ERREN_REG_MM_CRC_ERR_EN (1 << 1)
#define AD7124_ERREN_REG_ROM_CRC_ERR_EN (1 << 0)
/* Channel Registers 0-15 bits */
#define AD7124_CH_MAP_REG_CH_ENABLE (1 << 15)
#define AD7124_CH_MAP_REG_SETUP(x) (((x) & 0x7) << 12)
#define AD7124_CH_MAP_REG_AINP(x) (((x) & 0x1F) << 5)
#define AD7124_CH_MAP_REG_AINM(x) (((x) & 0x1F) << 0)
/* Configuration Registers 0-7 bits */
#define AD7124_CFG_REG_BIPOLAR (1 << 11)
#define AD7124_CFG_REG_BURNOUT(x) (((x) & 0x3) << 9)
#define AD7124_CFG_REG_REF_BUFP (1 << 8)
#define AD7124_CFG_REG_REF_BUFM (1 << 7)
#define AD7124_CFG_REG_AIN_BUFP (1 << 6)
#define AD7124_CFG_REG_AINN_BUFM (1 << 5)
#define AD7124_CFG_REG_REF_SEL(x) ((x) & 0x3) << 3
#define AD7124_CFG_REG_PGA(x) (((x) & 0x7) << 0)
/* Filter Register 0-7 bits */
#define AD7124_FILT_REG_FILTER(x) (((x) & 0x7) << 21)
#define AD7124_FILT_REG_REJ60 (1 << 20)
#define AD7124_FILT_REG_POST_FILTER(x) (((x) & 0x7) << 17)
#define AD7124_FILT_REG_SINGLE_CYCLE (1 << 16)
#define AD7124_FILT_REG_FS(x) (((x) & 0x7FF) << 0)
/******************************************************************************/
/*************************** Types Declarations *******************************/
/******************************************************************************/
/*! AD7124 registers list*/
typedef enum
{
AD7124_STATUS = 0X00, // 只读的状态寄存器,读取芯片状态
AD7124_ADC_CONTROL, // 控制寄存器,设置采样速率等
AD7124_DATA, // 数据寄存器,读取采样数据
AD7124_IOCON1, // 设置激励电流等参数用作RTD测试时可用
AD7124_IOCON2, // 使能偏置电压
AD7124_ID, // ID寄存器部分芯片的ID和手册上有所区别可用此寄存器测试SPI通讯
AD7124_ERROR, // 错误寄存器,读取错误信息,读写寄存器之前先读下该寄存器,检测芯片状态是否支持读写
AD7124_ERROR_EN, // 通过使能该寄存器的相应位来使能或者禁用诊断功能
AD7124_MCLK_COUNT, // 监控主时钟频率
AD7124_CHANNEL_0, // 设置AD采样通道和所需要的配置其中的Setup位决定了采用哪种Config、Filter、Offset、Gain寄存器的配置共有八种配置
AD7124_CHANNEL_1, // 通道寄存器的顺序并不是从AI0引脚读到最后一个引脚而是通过自己的设置来决定顺序
AD7124_CHANNEL_2,
AD7124_CHANNEL_3,
AD7124_CHANNEL_4,
AD7124_CHANNEL_5,
AD7124_CHANNEL_6,
AD7124_CHANNEL_7,
AD7124_CHANNEL_8,
AD7124_CHANNEL_9,
AD7124_CHANNEL_10,
AD7124_CHANNEL_11,
AD7124_CHANNEL_12,
AD7124_CHANNEL_13,
AD7124_CHANNEL_14,
AD7124_CHANNEL_15,
AD7124_CONFIG_0, // 配置极性,增益,基准选择等参数
AD7124_CONFIG_1,
AD7124_CONFIG_2,
AD7124_CONFIG_3,
AD7124_CONFIG_4,
AD7124_CONFIG_5,
AD7124_CONFIG_6,
AD7124_CONFIG_7,
AD7124_FILTER_0,
AD7124_FILTER_1, // 配置滤波器
AD7124_FILTER_2,
AD7124_FILTER_3,
AD7124_FILTER_4,
AD7124_FILTER_5,
AD7124_FILTER_6,
AD7124_FILTER_7,
AD7124_OFFSET_0,
AD7124_OFFSET_1,
AD7124_OFFSET_2,
AD7124_OFFSET_3,
AD7124_OFFSET_4,
AD7124_OFFSET_5,
AD7124_OFFSET_6,
AD7124_OFFSET_7,
AD7124_GAIN_0,
AD7124_GAIN_1,
AD7124_GAIN_2,
AD7124_GAIN_3,
AD7124_GAIN_4,
AD7124_GAIN_5,
AD7124_GAIN_6,
AD7124_GAIN_7,
AD7124_REG_NO
} ad7124_registers_addr_e; // 寄存器地址
typedef enum
{
AD7124_SIZE_1 = 1,
AD7124_SIZE_2 = 2,
AD7124_SIZE_3 = 3,
} ad7124_registers_size_e; // 寄存器字节大小
typedef enum
{
AD7124_RW = 1,
AD7124_R = 2,
AD7124_W = 3,
} ad7124_registers_rw_e; // 寄存器读写操作
typedef struct
{
int addr; // 寄存器地址ad7124_registers_e
int value; // 寄存器值
int size; // 寄存器字节大小
int rw; // 寄存器可执行的操作ad7124_registers_rw_e
} ad7124_st_reg_t; // AD7124寄存器结构体
typedef enum
{
STOP_NC_ADC = 0, // AD7124_CHANNEL_EN_2
STOP_NO_ADC, // AD7124_CHANNEL_EN_3
AI_IN1_ADC, // AD7124_CHANNEL_EN_4
AI_IN2_ADC, // AD7124_CHANNEL_EN_5
P1_DI2_ADC, // AD7124_CHANNEL_EN_6
P1_DI1_ADC, // AD7124_CHANNEL_EN_7
P1_AI_ADC, // AD7124_CHANNEL_EN_8
P2_DI2_ADC, // AD7124_CHANNEL_EN_9
P2_DI1_ADC, // AD7124_CHANNEL_EN_10
P2_AI_ADC, // AD7124_CHANNEL_EN_11
AD7124_CHANNEL_EN_MAX,
} ad7124_channel_e; // 该项目所使用的通道
typedef struct
{
uint8_t channel;
int32_t data; // 采样数据
float voltage; // 电压值
float current; // 电流值
} ad7124_analog_t; // 采样数据结构体
#define AD7124_CRC8_POLYNOMIAL_REPRESENTATION 0x07 /* x8 + x2 + x + 1 */
#define AD7124_DISABLE_CRC 0 // 默认关闭校验
#define AD7124_USE_CRC 1
#define AD7124_RDY 10000 // 等待时间
#define AD7124_RES 100 // 采样基准电阻
#define VREF 2.5f // 基准电压
#define GAIN 1 // 增益,该值和配置寄存器有关
#define AD_CODE 0XFFFFFF // 24位ADC
/*! Reads the value of the specified register. */
int32_t ad7124_read_register(ad7124_st_reg_t *p_reg); // 读寄存器
/*! Writes the value of the specified register. */
int32_t ad7124_write_register(ad7124_st_reg_t *reg); // 写寄存器
/*! Reads the value of the specified register without a device state check. */
int32_t ad7124_no_check_read_register(ad7124_st_reg_t *p_reg);
/*! Writes the value of the specified register without a device state check. */
int32_t ad7124_no_check_write_register(ad7124_st_reg_t *reg);
/*! Resets the device. */
int32_t ad7124_reset(void); // 复位ad7124芯片
/*! Waits until the device can accept read and write user actions. */
int32_t ad7124_wait_for_spi_ready(uint32_t timeout); // 读取ad7124芯片状态直到可以执行读写操作
/*! Waits until the device finishes the power-on reset operation. */
int32_t ad7124_wait_to_power_on(uint32_t timeout);
/*! Waits until a new conversion result is available. */
int32_t ad7124_wait_for_conv_ready(uint32_t timeout); // 等待转换完成
/*! Reads the conversion result from the device. */
int32_t ad7124_read_data(void);
void ad7124_get_analog(uint8_t channel_nr);
/*! Initializes the AD7124. */
int32_t ad7124_setup(void);
int32_t ad7124_read_write_spi(uint8_t *buff, uint8_t length);
#endif /* __AD7124_H__ */

154
DAC/dac161p997.c Normal file
View File

@ -0,0 +1,154 @@
#include "dac161p997.h"
#include "delay.h"
static dac161p997_t _handle;
static void _delay_us(uint32_t us)
{
delay_hardware_us(_handle.timer_us, us);
}
static void dac161p997_output_0()
{
_handle.io->set(*_handle.io);
_delay_us(DUTY_CYCLE_25);
_handle.io->reset(*_handle.io);
_delay_us(DUTY_CYCLE_75);
}
static void dac161p997_output_1()
{
_handle.io->set(*_handle.io);
_delay_us(DUTY_CYCLE_75);
_handle.io->reset(*_handle.io);
_delay_us(DUTY_CYCLE_25);
}
static void dac161p997_output_d()
{
_handle.io->set(*_handle.io);
_delay_us(DUTY_CYCLE_50);
_handle.io->reset(*_handle.io);
_delay_us(DUTY_CYCLE_50);
}
/**
* @brief DAC161符号
*
* DAC161输出函数
*
* @param sym ZERO_SYMONE_SYM或其他值
*/
static void dac161p997_output_symbol(uint8_t sym)
{
switch (sym)
{
case ZERO_SYM:
dac161p997_output_0();
break;
case ONE_SYM:
dac161p997_output_1();
break;
default:
dac161p997_output_d();
break;
}
}
/**
* @brief DAC161写入寄存器
*
* DAC161写入一个16位的数据8
*
* @param data 16
* @param tag 8tag = 0DAC寄存器tag = 1
*/
void dac161p997_swif_write_reg(uint16_t data, uint8_t tag)
{
uint8_t plow, phigh;
uint16_t i, tmp;
/* compute parity low */
tmp = data & 0x00ff; // get least significant byte
for (plow = 0; tmp != 0; tmp >>= 1)
{
if (tmp & 0x1) // test if lsb is 1
plow++; // count number of bits equal to 1
}
if (plow & 0x1) // check if number of 1s is odd
plow = 0; // set even parity
else
plow = 1; // else set odd parity
/* compute parity high */
tmp = (data & 0xff00) >> 8; // get most significant byte
for (phigh = 0; tmp != 0; tmp >>= 1)
{
if (tmp & 0x1) // test if lsb is 1
phigh++; // count number of bits equal to 1
}
if (phigh & 0x1) // check if number of 1s is odd
phigh = 0; // set even parity
else
phigh = 1; // set odd parity
phigh = phigh ^ tag; // parity high is for high slice = tag + 1 byte
dac161p997_output_symbol(IDLE_SYM); // Frame start: send an idle symbol first
dac161p997_output_symbol(tag);
tmp = data;
for (i = 0; i < 16; i++) // send 16 data bits msb to lsb
{
if (tmp & 0x8000)
{
dac161p997_output_symbol(ONE_SYM); // send 1
}
else
{
dac161p997_output_symbol(ZERO_SYM); // send 0
}
tmp = tmp << 1; // move next data bit to msb
}
dac161p997_output_symbol(phigh); // send parity high bit
dac161p997_output_symbol(plow); // send parity low bit
dac161p997_output_symbol(IDLE_SYM); // send idle
}
/**
* @brief DAC161输出电流
*
* DAC161写入指定的电流值来设置其输出电流,100ms
*
* @param current
*/
void dac161p997_output_current(float32 current)
{
uint16_t adc = (uint16_t)(current * DAC161P997_CURRENT_SLOPE);
dac161p997_swif_write_reg(adc, DACCODE_WRITE);
}
/**
* @brief DAC161设备
*
* DAC161设备便
*
*
* 1. DAC161的配置寄存器
* 2. DAC161的错误下限寄存器
* 3. DAC161的配置寄存器
*/
void dac161p997_init(TIM_TypeDef *timer_us)
{
DBG_ASSERT(timer_us != NULL __DBG_LINE);
_handle.timer_us = timer_us;
ENABLE_TIM_COUNT(_handle.timer_us);
_handle.io = gpio_create(DAC161P997_IO_PORT, DAC161P997_IO_PIN);
dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_UNLOCK, CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_CONFIG2_REG, CONFIG_WRITE);
dac161p997_swif_write_reg(DAC161P997_LCK_REG + DAC161P997_LCK_REG_LOCK, CONFIG_WRITE);
}

83
DAC/dac161p997.h Normal file
View File

@ -0,0 +1,83 @@
#ifndef __DAC161P997_H__
#define __DAC161P997_H__
#include "main.h"
#include "gpios.h"
#define DAC161P997_IO_PORT (DAC161P997_GPIO_Port)
#define DAC161P997_IO_PIN (DAC161P997_Pin)
#define DAC161P997_CURRENT_SLOPE 2730.625f // adc = (current / 24) * 0xffff
// Symbol Periods
#define DUTY_CYCLE_100 (1000U) // (CPU_CLK / BAUD_RATE)
#define DUTY_CYCLE_75 (DUTY_CYCLE_100 * 0.75f)
#define DUTY_CYCLE_50 (DUTY_CYCLE_100 * 0.50f)
#define DUTY_CYCLE_25 (DUTY_CYCLE_100 * 0.25f)
/************************************************************
* TI DAC161P997 REGISTER SET ADDRESSES
************************************************************/
#define DAC161P997_LCK_REG (0x0000)
#define DAC161P997_CONFIG1_REG (0x0100)
#define DAC161P997_CONFIG2_REG (0x0200)
#define DAC161P997_CONFIG3_REG (0x0300)
#define DAC161P997_ERR_LOW_REG (0x0400)
#define DAC161P997_ERR_HIGH_REG (0x0500)
// TI DAC161P997 Register Bits
#define DAC161P997_LCK_REG_LOCK (0x00AA) // any value other than 0x95
#define DAC161P997_LCK_REG_UNLOCK (0x0095)
#define DAC161P997_CONFIG1_REG_RST (0x0001)
#define DAC161P997_CONFIG1_REG_NOP (0 * 0x08u)
#define DAC161P997_CONFIG1_REG_SET_ERR (1 * 0x08u)
#define DAC161P997_CONFIG1_REG_CLEAR_ERR (2 * 0x08u)
#define DAC161P997_CONFIG1_REG_NOP3 (3 * 0x08u)
#define DAC161P997_CONFIG2_REG_LOOP (0x0001)
#define DAC161P997_CONFIG2_REG_CHANNEL (0x0002)
#define DAC161P997_CONFIG2_REG_PARITY (0x0004)
#define DAC161P997_CONFIG2_REG_FRAME (0x0008)
#define DAC161P997_CONFIG2_REG_ACK_EN (0x0010)
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_16 (0x000F)
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_8 (0x0007)
#define DAC161P997_CONFIG3_REG_RX_ERR_CNT_1 (0x0000)
// Tags
#define DACCODE_WRITE (0x00)
#define CONFIG_WRITE (0x01)
// Valid Symbols
#define ZERO_SYM (0x00)
#define ONE_SYM (0x01)
#define IDLE_SYM (0x02)
#define STATIC_LOW_SYM (0x03)
// DAC Codes for different currents
#define DACCODE_0mA (0x0000)
#define DACCODE_4mA (0x2AAA)
#define DACCODE_8mA (0x5555)
#define DACCODE_12mA (0x7FFF)
#define DACCODE_16mA (0xAAAA)
#define DACCODE_20mA (0xD555)
#define DACCODE_24mA (0xFFFF)
typedef enum
{
DAC161P997_IDLE_SYM,
} dac161p997_e;
typedef struct
{
TIM_TypeDef *timer_us;
gpio_t *io;
uint8_t count;
} dac161p997_t;
void dac161p997_output_0(void);
void dac161p997_output_1(void);
void dac161p997_output_d(void);
void dac161p997_output_symbol(uint8_t sym);
void dac161p997_swif_write_reg(uint16_t data, uint8_t tag);
extern void dac161p997_output_current(float32 current);
extern void dac161p997_init(TIM_TypeDef *timer_us);
#endif

56
DAC/dac161s997.c Normal file
View File

@ -0,0 +1,56 @@
#include "dac161s997.h"
/**
* @brief DAC161S997芯片写入寄存器值
*
* SPI接口向DAC161S997芯片写入指定的寄存器值
*
* @param dac_num DAC芯片编号
* @param reg
* @param data 16
*/
void dac161s997_write_reg(chip_type_e dac_num, uint8_t reg, uint16_t data)
{
uint8_t data_buffer[3] = {0, 0, 0};
data_buffer[0] = reg;
data_buffer[1] = data >> 8;
data_buffer[2] = data;
board_spi_init(dac_num); // 初始化SPI因为ADC芯片也用SPI1但是时序不同
board_spi_cs_on(dac_num);
spi_transmit_receive(&hspi1, data_buffer, 3);
board_spi_cs_off(dac_num);
}
/**
* @brief DAC161S997 DAC设备
*/
void dac161s997_init(void)
{
dac161s997_write_reg(DAC161S997_1, DAC161S997_ERR_LOW_REG, 0xFFFF);
dac161s997_write_reg(DAC161S997_1, DAC161S997_ERR_CONFIG_REG, 0x070E);
dac161s997_write_reg(DAC161S997_2, DAC161S997_ERR_LOW_REG, 0xFFFF);
dac161s997_write_reg(DAC161S997_2, DAC161S997_ERR_CONFIG_REG, 0x070E);
}
/**
* @brief DAC161S997芯片输出函数
*
* DAC161S997芯片的输出电流
*
* @param dac_num DAC芯片类型
* @param current
*/
void dac161s997_output(chip_type_e dac_num, float current)
{
uint32_t dac_code = (uint32_t)((current * 65535.0f) / 24.0f);
uint8_t data_buffer[3] = {0, 0, 0};
data_buffer[0] = DAC161S997_DACCODE_REG;
data_buffer[1] = dac_code >> 8;
data_buffer[2] = dac_code;
board_spi_init(dac_num); // 初始化SPI因为ADC芯片也用SPI1但是时序不同
board_spi_cs_on(dac_num);
spi_transmit_receive(&hspi1, data_buffer, 3);
board_spi_cs_off(dac_num);
}

28
DAC/dac161s997.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __DAC161S997_H__
#define __DAC161S997_H__
#include "main.h"
#include "user_spi.h"
/* Defines ********************************************************************/
/**
* @defgroup DAC161S997_REGS
* @{
*/
#define DAC161S997_XFR_REG 0x01 /**< Command: transfer data into register (protected write mode) */
#define DAC161S997_NOP_REG 0x02 /**< Command: does nothing except resetting the timeout timer */
#define DAC161S997_PROTECT_REG_WR_REG 0x03 /**< 1 means protected write mode in effect */
#define DAC161S997_DACCODE_REG 0x04 /**< 16 bit DAC code to be written */
#define DAC161S997_ERR_CONFIG_REG 0x05 /**< Configuration of error states */
#define DAC161S997_ERR_LOW_REG 0x06 /**< DAC code for the <4mA alarm level */
#define DAC161S997_ERR_HIGH_REG 0x07 /**< DAC code for the >20mA alarm level */
#define DAC161S997_RESET_REG 0x08 /**< Command: reset the chip */
#define DAC161S997_STATUS_REG 0x09 /**< Status of the chip */
#define DAC161S997_SPI SPI1
void dac161s997_write_reg(uint8_t dac_num, uint8_t reg, uint16_t data);
uint16_t dac161s997_read(uint8_t reg);
extern void dac161s997_init(void);
extern void dac161s997_output(uint8_t dac_num, float current);
#endif

0
README.md Normal file
View File

227
epprom/eeprom_fm24.c Normal file
View File

@ -0,0 +1,227 @@
/**
* @file eeprom_fm24.c
* @author xxx
* @date 2023-08-29 07:58:27
* @brief FM24 EEPROM相关的读写操作
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "eeprom_fm24.h"
#include "delay.h"
//========在此设定芯片地址=============
#define W_ADD_COM 0xa0 // 写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1 // 读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//=======在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
//=======在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
#define FM24_SPI SPI1
#define EEPROM_FM24_CS_PORT EE3_CS_GPIO_Port
#define EEPROM_FM24_CS_PIN EE3_CS_Pin
#define EEPROM_FM24_MOSI_PORT SPI_MOSI_GPIO_Port
#define EEPROM_FM24_MOSI_PIN SPI_MOSI_Pin
#define EEPROM_FM24_MISO_PORT SPI_MISO_GPIO_Port
#define EEPROM_FM24_MISO_PIN SPI_MISO_Pin
#define EEPROM_FM24_SCK_PORT SPI_CLK_GPIO_Port
#define EEPROM_FM24_SCK_PIN SPI_CLK_Pin
static fm24_t _eeprom_fm24;
void eeprom_fm24_init(void)
{
spi_gpio_group_t gpios;
spi_normal_config_t cfg;
osel_memset((uint8_t *)&cfg, 0, sizeof(spi_normal_config_t));
// 创建CS引脚
gpios.cs = gpio_create(EEPROM_FM24_CS_PORT, EEPROM_FM24_CS_PIN);
gpios.mosi = gpio_create(EEPROM_FM24_MOSI_PORT, EEPROM_FM24_MOSI_PIN);
gpios.sck = gpio_create(EEPROM_FM24_SCK_PORT, EEPROM_FM24_SCK_PIN);
gpios.miso = gpio_create(EEPROM_FM24_MISO_PORT, EEPROM_FM24_MISO_PIN);
gpios.rst = gpio_create(NULL, 0);
gpios.rdy = gpio_create(NULL, 0);
// 创建SPI对象
eeprom_fm24_get()->spi = spi_create(SPI_TYPE_NORMAL, gpios, 0);
DBG_ASSERT(eeprom_fm24_get() != NULL __DBG_LINE);
cfg.cmd_rdsr = FM24_CMD_RDSR;
cfg.cmd_wrsr = FM24_CMD_WRSR;
cfg.cmd_wren = FM24_CMD_WREN;
cfg.cmd_wrdi = FM24_CMD_WRDI;
cfg.cmd_write = FM24_CMD_WRITE;
cfg.cmd_read = FM24_CMD_READ;
cfg.dummy_byte = FM24_DUMMY_BYTE;
cfg.address_bytes = 2;
cfg.page_size = FM24_PAGE_SIZE;
cfg.total_size = FM24_SIZE;
cfg.continuous_write = FALSE;
osel_memcpy((uint8_t *)&eeprom_fm24_get()->spi->cfg, (uint8_t *)&cfg, sizeof(spi_normal_config_t));
// 使能SPI
eeprom_fm24_get()->spi->interface.hardware_enable(eeprom_fm24_get()->spi, FM24_SPI);
// 这里需要复位下SPI否则读出的数据不对
eeprom_fm24_get()->spi->interface.u.normal.spi_reset(eeprom_fm24_get()->spi);
eeprom_fm24_write_protection_close();
// eeprom_fm24_test();
}
fm24_t *eeprom_fm24_get(void)
{
return &_eeprom_fm24;
}
void eeprom_fm24_dinit(void)
{
LL_SPI_Disable(FM24_SPI);
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.mosi->port, eeprom_fm24_get()->spi->gpios.mosi->pin);
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.miso->port, eeprom_fm24_get()->spi->gpios.miso->pin);
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.sck->port, eeprom_fm24_get()->spi->gpios.sck->pin);
GPIO_SET_ANALOG(eeprom_fm24_get()->spi->gpios.cs->port, eeprom_fm24_get()->spi->gpios.cs->pin);
}
void eeprom_fm24_enable(void)
{
uint16_t count = 100;
LL_SPI_Enable(FM24_SPI);
// 判断SPI是否使能成功
while (LL_SPI_IsEnabled(FM24_SPI) != 1)
{
if (count-- == 0)
{
return;
}
else
{
__NOP();
}
}
}
void eeprom_fm24_disable(void)
{
uint16_t count = 100;
LL_SPI_Disable(FM24_SPI);
// 判断SPI是否关闭成功
while (LL_SPI_IsEnabled(FM24_SPI) != 0)
{
if (count-- == 0)
{
return;
}
else
{
__NOP();
}
}
}
/**
* @brief EEPROM FM24的写保护
*
* EEPROM FM24的写保护功能
*
* EEPROM FM24的SPI接口已正确初始化
*/
void eeprom_fm24_write_protection_close(void)
{
DBG_ASSERT(eeprom_fm24_get()->spi != NULL __DBG_LINE);
eeprom_fm24_enable();
eeprom_fm24_get()->spi->interface.u.normal.spi_write_reg(eeprom_fm24_get()->spi, eeprom_fm24_get()->spi->cfg.cmd_wrsr, 0);
eeprom_fm24_disable();
}
/**
* @brief EEPROM FM24的写保护状态
*
* EEPROM FM24的写保护状态
*
* @return BOOL TRUE表示没有写保护FALSE表示有写保护
*/
BOOL eeprom_fm24_write_protection_state(void)
{
DBG_ASSERT(eeprom_fm24_get()->spi != NULL __DBG_LINE);
eeprom_fm24_enable();
eeprom_fm24_get()->write_protection.data = eeprom_fm24_get()->spi->interface.u.normal.spi_read_reg(eeprom_fm24_get()->spi, eeprom_fm24_get()->spi->cfg.cmd_rdsr);
eeprom_fm24_disable();
if (eeprom_fm24_get()->write_protection.bits.bp0 == 1 ||
eeprom_fm24_get()->write_protection.bits.bp1 == 1 ||
eeprom_fm24_get()->write_protection.bits.wpen == 1)
{
return FALSE;
}
else
{
return TRUE;
}
}
BOOL eeprom_fm24_write(uint32_t write_addr, uint8_t *data, uint16_t length)
{
BOOL ret = FALSE;
if (length == 0)
{
return ret;
}
// 开启和关闭SPI对读写实时性有影响
eeprom_fm24_enable();
ret = eeprom_fm24_get()->spi->interface.u.normal.spi_write(eeprom_fm24_get()->spi, write_addr, data, length);
eeprom_fm24_disable();
return ret;
}
BOOL eeprom_fm24_read(uint32_t read_addr, uint8_t *data, uint16_t length)
{
BOOL ret = FALSE;
if (length == 0)
{
return ret;
}
// 开启和关闭SPI对读写实时性有影响
eeprom_fm24_enable();
ret = eeprom_fm24_get()->spi->interface.u.normal.spi_read(eeprom_fm24_get()->spi, read_addr, data, length);
eeprom_fm24_disable();
return ret;
}
BOOL eeprom_fm24_test(void)
{
const uint8_t buf_size = 5;
uint16_t test_address = FM24_TEST_PAGE * FM24_PAGE_SIZE;
uint8_t buf[buf_size];
uint8_t rbuf[buf_size];
osel_memset(buf, 0, buf_size);
osel_memset(rbuf, 0, buf_size);
buf[0] = 0xD5;
buf[1] = 0xC8;
buf[2] = 0x00;
buf[3] = 0x01;
buf[4] = 0x02;
buf[buf_size - 1] = 0xfe;
eeprom_fm24_write(test_address, buf, buf_size);
__NOP();
eeprom_fm24_read(test_address, rbuf, buf_size);
if (osel_memcmp(buf, rbuf, buf_size) == 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
/**
* @brief FM24 EEPROM的状态
*
* FM24 EEPROM的当前状态TRUEEEPROM正常工作
*
* @return BOOL TRUE
*/
BOOL eeprom_fm24_status_get(void)
{
return TRUE;
}

153
epprom/eeprom_fm24.h Normal file
View File

@ -0,0 +1,153 @@
/**
* @file eeprom_fm24.h
* @author xxx
* @date 2023-08-30 14:05:55
* @brief FM24系列EEPROM驱动 https://zhuanlan.zhihu.com/p/598934638
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __EEPROM_FM24_H__
#define __EEPROM_FM24_H__
#include "main.h"
#include "spis.h"
/**
* High-endurance 100 trillion (1014) read/writes
* 151-year data retention
* NoDelay writes
*/
#define e2prom 256 //
#if e2prom == 1
#define FM24_PAGE_SIZE 16
#define FM24_SIZE (128 * 8)
#elif e2prom == 2
#define FM24_PAGE_SIZE 16
#define FM24_SIZE (256 * 8)
#elif e2prom == 4
#define FM24_PAGE_SIZE 32
#define FM24_SIZE (512 * 8)
#elif e2prom == 8
#define FM24_PAGE_SIZE 64
#define FM24_SIZE (1024 * 8)
#elif e2prom == 16
#define FM24_PAGE_SIZE 128
#define FM24_SIZE (2048 * 8)
#elif e2prom == 32
#define FM24_PAGE_SIZE 128
#define FM24_SIZE (4096 * 8)
#elif e2prom == 64
#define FM24_PAGE_SIZE 256
#define FM24_SIZE (8192 * 8)
#elif e2prom == 128
#define FM24_PAGE_SIZE 256
#define FM24_SIZE (16384)
#elif e2prom == 256
#define FM24_PAGE_SIZE 256
#define FM24_SIZE (32768) // 32K 128页
#define FM24_PAGE_NUM 128
#elif e2prom == 512
#define FM24_PAGE_SIZE 512
#define FM24_SIZE (65536)
#endif
#define FM24_CMD_RDSR 0x05 /*!< Read Status Register instruction */
#define FM24_CMD_WRSR 0x01 /*!< Write Status Register instruction */
#define FM24_CMD_WREN 0x06 /*!< Write enable instruction */
#define FM24_CMD_WRDI 0x04 /*!< Write disable instruction */
#define FM24_CMD_READ 0x03 /*!< Read from Memory instruction */
#define FM24_CMD_WRITE 0x02 /*!< Write to Memory instruction */
#define FM24_DUMMY_BYTE 0x00 ///< 无用数据
#define FM24_TEST_PAGE 0 ///< 测试页地址
typedef union
{
uint8_t data;
struct
{
uint8_t reserve1 : 1;
uint8_t wel : 1; ///< Write enable latch
uint8_t bp0 : 1; ///< Block protect 0
uint8_t bp1 : 1; ///< Block protect 1
uint8_t reserve2 : 3;
uint8_t wpen : 1; ///< Write protect enable
} bits;
} fm24_write_protection_u;
typedef struct
{
fm24_write_protection_u write_protection;
spi_t *spi;
} fm24_t;
/**
* @brief Initializes the FM24 EEPROM module.
*/
extern void eeprom_fm24_init(void);
/**
* @brief Deinitializes the FM24 EEPROM module.
*/
extern void eeprom_fm24_dinit(void);
/**
* @brief Gets the fm24_t handle of the FM24 EEPROM module.
* @return The fm24_t handle of the FM24 EEPROM module.
*/
extern fm24_t *eeprom_fm24_get(void);
/**
* @brief Enables the FM24 EEPROM module.
*/
extern void eeprom_fm24_enable(void);
/**
* @brief Disables the FM24 EEPROM module.
*/
extern void eeprom_fm24_disable(void);
/**
* @brief Reads data from the FM24 EEPROM module.
* @param read_addr The starting address to read from.
* @param data Pointer to the buffer to store the read data.
* @param length The number of bytes to read.
* @return TRUE if the read operation is successful, FALSE otherwise.
*/
extern BOOL eeprom_fm24_read(uint32_t read_addr, uint8_t *data, uint16_t length);
/**
* @brief Writes data to the FM24 EEPROM module.
* @param write_addr The starting address to write to.
* @param data Pointer to the data to be written.
* @param length The number of bytes to write.
* @return TRUE if the write operation is successful, FALSE otherwise.
*/
extern BOOL eeprom_fm24_write(uint32_t write_addr, uint8_t *data, uint16_t length);
/**
* @brief Closes the write protection of the FM24 EEPROM module.
*/
extern void eeprom_fm24_write_protection_close(void);
/**
* @brief Gets the write protection state of the FM24 EEPROM module.
* @return TRUE if the FM24 EEPROM module is not write-protected, FALSE otherwise.
*/
extern BOOL eeprom_fm24_write_protection_state(void);
/**
* @brief Performs a test on the FM24 EEPROM module.
*/
extern BOOL eeprom_fm24_test(void);
/**
* @brief Gets the status of the FM24 EEPROM module.
* @return TRUE if the FM24 EEPROM module is ready, FALSE otherwise.
*/
extern BOOL eeprom_fm24_status_get(void);
#endif // __EEPROM_FM24_H__

172
epprom/eeprom_lc02b.c Normal file
View File

@ -0,0 +1,172 @@
#include "eeprom_lc02b.h"
#include "delay.h"
#include "i2cs.h"
#define W_ADD_COM 0xa8 // 写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa9 // 读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
#define PAGE_SIZE 8U
#define SIZE 256U
#define EEPROM_LC02B_SDA_PORT I2C1_SDA_GPIO_Port
#define EEPROM_LC02B_SDA_PIN I2C1_SDA_Pin
#define EEPROM_LC02B_SCL_PORT I2C1_SCL_GPIO_Port
#define EEPROM_LC02B_SCL_PIN I2C1_SCL_Pin
static i2c_t *_eeprom_24lc028bt_i2c;
static TIM_TypeDef *_timer_us;
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
void eeprom_lc02b_test(void)
{
#define TEST_SIZE 15
uint16_t test_address = SIZE - TEST_SIZE;
uint8_t buf[TEST_SIZE];
for (uint8_t i = 0; i < TEST_SIZE; i++)
{
buf[i] = i + 1;
}
eeprom_lc02b_write(test_address, buf, TEST_SIZE);
_delay_us(10000);
osel_memset(buf, 0, ARRAY_LEN(buf));
eeprom_lc02b_read(test_address, buf, TEST_SIZE);
__NOP();
}
/**
* @brief EEPROM LC02B的状态
*
* EEPROM LC02B的当前状态
*
* @return EEPROM LC02B处于正常状态TRUEFALSE
* TRUE
*/
BOOL eeprom_lc02b_status_get(void)
{
return TRUE;
}
/**
* @brief EEPROM LC02B初始化
* @return {*}
* @note
*/
void eeprom_lc02b_init(TIM_TypeDef *timer_us)
{
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios;
gpios.scl = gpio_create(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN);
gpios.sda = gpio_create(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN);
_eeprom_24lc028bt_i2c = i2c_create(gpios, 10);
// eeprom_lc02b_test();
}
/**
* @brief EEPROM LC02B反初始化
* @return {*}
* @note
*/
void eeprom_lc02b_dinit(void)
{
GPIO_SET_ANALOG(EEPROM_LC02B_SDA_PORT, EEPROM_LC02B_SDA_PIN);
GPIO_SET_ANALOG(EEPROM_LC02B_SCL_PORT, EEPROM_LC02B_SCL_PIN);
}
/**
* @brief
* @param {uint32_t} write_addr
* @param {uint8_t} *data
* @param {uint16_t} length
* @return {*}
* @note
*/
void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length)
{
// 发送开始信号
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送写入地址命令
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
// 等待写入地址命令响应
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送要写入的地址
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 循环写入数据
for (uint16_t i = 0; i < length; i++)
{
// 写入一个字节数据
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, *data++);
// 等待响应
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
write_addr++;
if (write_addr % PAGE_SIZE == 0)
{
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
_delay_us(10000); // 延时10ms等待写入完成
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)write_addr);
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
}
}
// 写入完成停止I2C总线
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
}
/**
* @brief
* @param {uint32_t} read_addr
* @param {uint8_t} *data
* @param {uint16_t} length
* @return {*}
* @note
*/
void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length)
{
// 发送开始信号
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送写入地址命令
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, W_ADD_COM);
// 等待写入地址命令响应
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送要读取的地址
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, (uint8_t)read_addr);
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 发送开始信号
_eeprom_24lc028bt_i2c->interface.start(_eeprom_24lc028bt_i2c);
// 发送读取地址命令
_eeprom_24lc028bt_i2c->interface.write_byte(_eeprom_24lc028bt_i2c, R_ADD_COM);
// 等待读取地址命令响应
_eeprom_24lc028bt_i2c->interface.wait_ack(_eeprom_24lc028bt_i2c);
// 循环读取数据
for (uint16_t i = 0; i < length - 1; i++)
{
// 读取一个字节数据
*data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, TRUE);
}
*data++ = _eeprom_24lc028bt_i2c->interface.read_byte(_eeprom_24lc028bt_i2c, FALSE);
// 停止I2C总线
_eeprom_24lc028bt_i2c->interface.stop(_eeprom_24lc028bt_i2c);
}

60
epprom/eeprom_lc02b.h Normal file
View File

@ -0,0 +1,60 @@
/**
* @file eeprom_lc02b.h
* @author xxx
* @date 2023-12-27 14:44:02
* @brief
* @copyright Copyright (c) 2024 by xxx, All Rights Reserved.
*/
#ifndef __EEPROM_LC02B_H
#define __EEPROM_LC02B_H
#include "main.h"
/**
* is a 2 Kbit Electrically Erasable PROM. The LC02B EEPROM is organized as 256 x 8 bits. 256 bytes
* Data Retention >200 Years
* More than 1 Million Erase/Write Cycles
* Page Write Time 3 ms, typical
*/
/**
* @brief Initializes the LC02B EEPROM module.
*/
void eeprom_lc02b_init(TIM_TypeDef *timer_us);
/**
* @brief Deinitializes the LC02B EEPROM module.
*/
void eeprom_lc02b_dinit(void);
/**
* @brief Writes data to the LC02B EEPROM module.
*
* @param write_addr The starting address to write the data.
* @param data The pointer to the data to be written.
* @param length The length of the data to be written.
*/
void eeprom_lc02b_write(uint32_t write_addr, uint8_t *data, uint16_t length);
/**
* @brief Reads data from the LC02B EEPROM module.
*
* @param read_addr The starting address to read the data.
* @param data The pointer to store the read data.
* @param length The length of the data to be read.
*/
void eeprom_lc02b_read(uint32_t read_addr, uint8_t *data, uint16_t length);
/**
* @brief Performs a test on the LC02B EEPROM module.
*/
void eeprom_lc02b_test(void);
/**
* @brief Gets the LC02B EEPROM status.
*
* This function is used to get the current status of the LC02B EEPROM.
*
* @return TRUE if the LC02B EEPROM is in normal status, FALSE otherwise.
*/
BOOL eeprom_lc02b_status_get(void);
#endif ///< !__EEPROM_LC02B_H

330
epprom/eeprom_m95.c Normal file
View File

@ -0,0 +1,330 @@
/**
* @file eeprom_m95.c
* @author xxx
* @date 2023-08-30 08:58:43
* @brief M95 EEPROM相关的读写操作
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "eeprom_m95.h"
#include "spis.h"
#include "delay.h"
#include "storage.h"
#define M95_SPI SPI1
#define EEPROM_M95_1_CS_PORT EE1_CS_GPIO_Port
#define EEPROM_M95_1_CS_PIN EE1_CS_Pin
#define EEPROM_M95_2_CS_PORT EE2_CS_GPIO_Port
#define EEPROM_M95_2_CS_PIN EE2_CS_Pin
// 下面宏定义为2个EEPROM_M95的引脚定义
#define EEPROM_M95_MOSI_PORT SPI_MOSI_GPIO_Port
#define EEPROM_M95_MOSI_PIN SPI_MOSI_Pin
#define EEPROM_M95_MISO_PORT SPI_MISO_GPIO_Port
#define EEPROM_M95_MISO_PIN SPI_MISO_Pin
#define EEPROM_M95_SCK_PORT SPI_CLK_GPIO_Port
#define EEPROM_M95_SCK_PIN SPI_CLK_Pin
#define M95_TEST_PAGE (M95_PAGE_SIZE_256 - 1) ///< 测试页地址
m95_number_t eeprom_m95s[M95_MAX];
/**
* @brief EEPROM_M95eeprom_m95s
* @param {m95_number_e} num
* @return {*}
* @note
*/
void eeprom_m95_init(m95_number_e num)
{
DBG_ASSERT(num < M95_MAX __DBG_LINE);
spi_gpio_group_t gpios;
spi_t *eeprom_m95_spi;
spi_normal_config_t cfg;
osel_memset((uint8_t *)&cfg, 0, sizeof(spi_normal_config_t));
cfg.cmd_rdsr = M95_CMD_RDSR;
cfg.cmd_wrsr = M95_CMD_WRSR;
cfg.cmd_wren = M95_CMD_WREN;
cfg.cmd_wrdi = M95_CMD_WRDI;
cfg.cmd_write = M95_CMD_WRITE;
cfg.cmd_read = M95_CMD_READ;
cfg.dummy_byte = M95_DUMMY_BYTE;
cfg.continuous_write = FALSE;
// 128 byte
if (num == M95_1)
{
// 创建CS引脚
gpios.cs = gpio_create(EEPROM_M95_1_CS_PORT, EEPROM_M95_1_CS_PIN);
cfg.address_bytes = 3;
cfg.page_size = M95_PAGE_SIZE_256;
cfg.total_size = _M95M02_;
}
// 256 byte
else if (num == M95_2)
{
// 创建CS引脚
gpios.cs = gpio_create(EEPROM_M95_2_CS_PORT, EEPROM_M95_2_CS_PIN);
cfg.address_bytes = 3;
cfg.page_size = M95_PAGE_SIZE_256;
cfg.total_size = _M95M02_;
}
else
{
DBG_ASSERT(FALSE __DBG_LINE);
}
gpios.mosi = gpio_create(EEPROM_M95_MOSI_PORT, EEPROM_M95_MOSI_PIN);
gpios.sck = gpio_create(EEPROM_M95_SCK_PORT, EEPROM_M95_SCK_PIN);
gpios.miso = gpio_create(EEPROM_M95_MISO_PORT, EEPROM_M95_MISO_PIN);
gpios.rst = gpio_create(NULL, 0);
gpios.rdy = gpio_create(NULL, 0);
// 创建SPI对象
eeprom_m95_spi = spi_create(SPI_TYPE_NORMAL, gpios, 10);
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
osel_memcpy((uint8_t *)&eeprom_m95_spi->cfg, (uint8_t *)&cfg, sizeof(spi_normal_config_t));
// 使能SPI
eeprom_m95_spi->interface.hardware_enable(eeprom_m95_spi, M95_SPI);
eeprom_m95s[num].num = num;
eeprom_m95s[num].spi = eeprom_m95_spi;
// 这里需要设置,否则读出的数据不对
eeprom_m95_spi->interface.u.normal.spi_reset(eeprom_m95_spi);
eeprom_m95_write_protection_close(num); // 关闭写保护
// eeprom_m95_test(num);
}
/**
* @brief EEPROM_M95
* @param {m95_number_e} num
* @return {*}
* @note
*/
void eeprom_m95_dinit(m95_number_e num)
{
LL_SPI_Disable(M95_SPI);
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.mosi->port, eeprom_m95s[num].spi->gpios.mosi->pin);
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.miso->port, eeprom_m95s[num].spi->gpios.miso->pin);
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.sck->port, eeprom_m95s[num].spi->gpios.sck->pin);
GPIO_SET_ANALOG(eeprom_m95s[num].spi->gpios.cs->port, eeprom_m95s[num].spi->gpios.cs->pin);
}
/**
* @brief M95 EEPROM使能
* @return {*}
* @note
*/
void eeprom_m95_enable(void)
{
uint16_t count = 100;
LL_SPI_Enable(M95_SPI);
// 判断SPI是否使能成功
while (LL_SPI_IsEnabled(M95_SPI) != 1)
{
if (count-- == 0)
{
return;
}
else
{
__NOP();
}
}
}
/**
* @brief M95 EEPROM失能
* @return {*}
* @note
*/
void eeprom_m95_disable(void)
{
uint16_t count = 100;
LL_SPI_Disable(M95_SPI);
// 判断SPI是否关闭成功
while (LL_SPI_IsEnabled(M95_SPI) != 0)
{
if (count-- == 0)
{
return;
}
else
{
__NOP();
}
}
}
/**
* @brief EEPROM M95写保护
*
* M95 EEPROM的写保护功能
*
* @param num M95 EEPROM的编号
*/
void eeprom_m95_write_protection_close(m95_number_e num)
{
spi_t *handle = eeprom_m95s[num].spi;
DBG_ASSERT(handle != NULL __DBG_LINE);
eeprom_m95_enable();
handle->interface.u.normal.spi_write_reg(handle, handle->cfg.cmd_wrsr, 0);
eeprom_m95_disable();
}
/**
* @brief M95 EEPROM写保护状态()
*
* M95编号获取其写保护状态
*
* @param num M95编号
* @return M95 EEPROM处于写保护状态FALSETRUE
*/
BOOL eeprom_m95_write_protection_state(m95_number_e num)
{
spi_t *handle = eeprom_m95s[num].spi;
DBG_ASSERT(handle != NULL __DBG_LINE);
eeprom_m95_enable();
eeprom_m95s[num].write_protection.data = handle->interface.u.normal.spi_read_reg(handle, handle->cfg.cmd_rdsr);
eeprom_m95_disable();
if (eeprom_m95s[num].write_protection.bits.bp0 == 1 ||
eeprom_m95s[num].write_protection.bits.bp1 == 1 ||
eeprom_m95s[num].write_protection.bits.srwd == 1)
{
return FALSE;
}
else
{
return TRUE;
}
}
/**
* @brief M95 EEPROM内存数据
* @param num EEPROM模块编号01
* @param read_addr
* @param data
* @param length
* @return {*}
*/
BOOL eeprom_m95_read(m95_number_e num, uint32_t read_addr, uint8_t *data, uint16_t length)
{
BOOL ret = FALSE;
if (length == 0)
{
return ret;
}
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi; // 获取EEPROM模块的SPI配置
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
// 开启和关闭SPI对读写实时性有影响
eeprom_m95_enable();
ret = eeprom_m95_spi->interface.u.normal.spi_read(eeprom_m95_spi, read_addr, data, length);
eeprom_m95_disable();
return ret;
}
/**
* @brief M95 EEPROM内存写入数据
* @param num EEPROM模块编号01
* @param write_addr
* @param data
* @param length
* @return {*}
*/
BOOL eeprom_m95_write(m95_number_e num, uint32_t write_addr, uint8_t *data, uint16_t length)
{
BOOL ret = FALSE;
if (length == 0)
{
return ret;
}
spi_t *eeprom_m95_spi = eeprom_m95s[num].spi;
DBG_ASSERT(eeprom_m95_spi != NULL __DBG_LINE);
// 开启和关闭SPI对读写实时性有影响
eeprom_m95_enable();
ret = eeprom_m95_spi->interface.u.normal.spi_write(eeprom_m95_spi, write_addr, data, length);
eeprom_m95_disable();
return ret;
}
BOOL eeprom_m95_1_read(uint32_t addr, uint8_t *buf, uint16_t size)
{
return eeprom_m95_read(M95_1, addr, buf, size);
}
BOOL eeprom_m95_1_write(uint32_t addr, uint8_t *buf, uint16_t size)
{
return eeprom_m95_write(M95_1, addr, (uint8_t *)buf, size);
}
BOOL eeprom_m95_2_read(uint32_t addr, uint8_t *buf, uint16_t size)
{
return eeprom_m95_read(M95_2, addr, buf, size);
}
BOOL eeprom_m95_2_write(uint32_t addr, uint8_t *buf, uint16_t size)
{
return eeprom_m95_write(M95_2, addr, (uint8_t *)buf, size);
}
/**
* @brief M95 EEPROM测试
* @param {m95_number_e} num
* @return {*}
* @note
*/
BOOL eeprom_m95_test(m95_number_e num)
{
const uint8_t buf_size = 5;
storage_t *st = storage_init(M95_TEST_PAGE * M95_PAGE_SIZE_256, M95_PAGE_SIZE_256);
DBG_ASSERT(st != NULL __DBG_LINE);
if (num == M95_1)
{
st->ops.read = eeprom_m95_1_read;
st->ops.write = eeprom_m95_1_write;
}
else
{
st->ops.read = eeprom_m95_2_read;
st->ops.write = eeprom_m95_2_write;
}
uint8_t buf[buf_size];
uint8_t rbuf[buf_size];
storage_add_node(st, 0, buf_size);
osel_memset(buf, 0, buf_size);
buf[0] = 0xD5;
buf[1] = 0xC8;
buf[2] = num;
buf[3] = 0xaa;
buf[4] = 0xbb;
storage_write(st, 0, buf);
__NOP();
storage_read(st, 0, rbuf);
storage_destroy(st);
if (osel_memcmp(buf, rbuf, buf_size) == 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
/**
* @brief EEPROM M95状态
*
* EEPROM M95设备的工作状态
*
* @param num EEPROM M95设备编号
*
* @return EEPROM M95设备正常工作TRUEFALSE
*/
BOOL eeprom_m95_status_get(m95_number_e num)
{
return TRUE;
}

168
epprom/eeprom_m95.h Normal file
View File

@ -0,0 +1,168 @@
/**
* @file eeprom_m95.h
* @author xxx
* @date 2023-08-30 14:05:55
* @brief eeprom_m95.h
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __EEPROM_M95_H
#define __EEPROM_M95_H
#include "main.h"
#include "spis.h"
/**
* Byte Write within 10 ms
* More than 4 million Write cycles
* More than 200-year data retention
*/
#define _M95010_ 128
#define _M95020_ 256
#define _M95040_ 512
#define _M95080_ 1024
#define _M95160_ 2048
#define _M95320_ 4096
#define _M95640_ 8192
#define _M95128_ 16384
#define _M95256_ 32768
#define _M95512_ 65536 ///< 65K
#define _M95M02_ 262144 ///< 256K 262144/256 = 1024
#define M95_CMD_RDSR 0x05 /*!< Read Status Register instruction */
#define M95_CMD_WRSR 0x01 /*!< Write Status Register instruction */
#define M95_CMD_WREN 0x06 /*!< Write enable instruction */
#define M95_CMD_WRDI 0x04 /*!< Write disable instruction */
#define M95_CMD_READ 0x03 /*!< Read from Memory instruction */
#define M95_CMD_WRITE 0x02 /*!< Write to Memory instruction */
///< Instruction available only for the M95_2-D device.
#define M95_CMD_RDID 0x83 /*!< Read identification page*/
#define M95_CMD_WRID 0x82 /*!< Write identification page*/
#define M95_CMD_RDLS 0x83 /*!< Reads the Identification page lock status*/
#define M95_CMD_LID 0x82 /*!< Locks the Identification page in read-only mode*/
#define M95_DUMMY_BYTE 0xA5 ///< 虚拟字节
///< 定义存储器大小(Bytes)
typedef enum
{
M95_PAGE_SIZE_16 = 16, ///< _M95010_ 、_M95020_ 、_M95040_
M95_PAGE_SIZE_32 = 32, ///< _M95080_ 、_M95160_、_M95320_、_M95640_
M95_PAGE_SIZE_64 = 64, ///< _M95128_、_M95256_
M95_PAGE_SIZE_128 = 128, ///< _M95512_
M95_PAGE_SIZE_256 = 256, ///< _M95M02_
} m95_page_size_e;
typedef enum
{
M95_1,
M95_2,
M95_MAX,
} m95_number_e; ///< 板卡上2块m95芯片定义
typedef union
{
uint8_t data;
struct
{
uint8_t wip : 1; ///< Write in progress
uint8_t wel : 1; ///< Write enable latch
uint8_t bp0 : 1; ///< Block protect 0
uint8_t bp1 : 1; ///< Block protect 1
uint8_t reserve : 3;
uint8_t srwd : 1; ///< Status register write protect
} bits;
} m95_write_protection_u;
typedef struct
{
m95_number_e num;
m95_write_protection_u write_protection;
spi_t *spi;
} m95_number_t;
extern m95_number_t eeprom_m95s[M95_MAX]; ///< m95芯片数组
/**
* @brief Initializes the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern void eeprom_m95_init(m95_number_e num);
/**
* @brief Deinitializes the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern void eeprom_m95_dinit(m95_number_e num);
/**
* @brief Enables the M95 EEPROM module.
*/
extern void eeprom_m95_enable(void);
/**
* @brief Disables the M95 EEPROM module.
*/
extern void eeprom_m95_disable(void);
/**
* @brief Closes the write protection of the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern void eeprom_m95_write_protection_close(m95_number_e num);
/**
* @brief write protection state of the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern BOOL eeprom_m95_write_protection_state(m95_number_e num);
/**
* @brief Reads data from the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
* @param read_addr The address to read from.
* @param data The buffer to store the read data.
* @param length The number of bytes to read.
*/
extern BOOL eeprom_m95_read(m95_number_e num, uint32_t read_addr, uint8_t *data, uint16_t length);
/**
* @brief Writes data to the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
* @param write_addr The address to write to.
* @param data The data to write.
* @param length The number of bytes to write.
*/
extern BOOL eeprom_m95_write(m95_number_e num, uint32_t write_addr, uint8_t *data, uint16_t length);
/**
* @brief Performs a test on the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern BOOL eeprom_m95_test(m95_number_e num);
/**
* @brief Gets the status of the M95 EEPROM module.
*
* @param num The M95 EEPROM number.
*/
extern BOOL eeprom_m95_status_get(m95_number_e num);
extern BOOL eeprom_m95_1_read(uint32_t addr, uint8_t *buf, uint16_t size);
extern BOOL eeprom_m95_1_write(uint32_t addr, uint8_t *buf, uint16_t size);
extern BOOL eeprom_m95_2_read(uint32_t addr, uint8_t *buf, uint16_t size);
extern BOOL eeprom_m95_2_write(uint32_t addr, uint8_t *buf, uint16_t size);
#endif ///< __EEPROM_M95_H

68
gp8302.c Normal file
View File

@ -0,0 +1,68 @@
#include "gp8302.h"
#define I2C_GP8302_1_SCL_PORT I2C2_SCL_GPIO_Port
#define I2C_GP8302_1_SCL_PIN I2C2_SCL_Pin
#define I2C_GP8302_1_SDA_PORT I2C2_SDA_GPIO_Port
#define I2C_GP8302_1_PIN I2C2_SDA_Pin
#define I2C_GP8302_1_DETECTION_PORT ALARM1_GPIO_Port
#define I2C_GP8302_1_DETECTION_PIN ALARM1_Pin
#define I2C_GP8302_2_SCL_PORT I2C3_SCL_GPIO_Port
#define I2C_GP8302_2_SCL_PIN I2C3_SCL_Pin
#define I2C_GP8302_2_SDA_PORT I2C3_SDA_GPIO_Port
#define I2C_GP8302_2_PIN I2C3_SDA_Pin
#define I2C_GP8302_2_DETECTION_PORT ALARM2_GPIO_Port
#define I2C_GP8302_2_DETECTION_PIN ALARM2_Pin
static gp8302_t gp8302[GP8302_MAX];
void gp8302_init(void)
{
i2c_gpio_group_t gpios;
gpios.scl = gpio_create(I2C_GP8302_1_SCL_PORT, I2C_GP8302_1_SCL_PIN);
gpios.sda = gpio_create(I2C_GP8302_1_SDA_PORT, I2C_GP8302_1_PIN);
gp8302[GP8302_1].i2c = i2c_create(gpios, 0);
gpios.scl = gpio_create(I2C_GP8302_2_SCL_PORT, I2C_GP8302_2_SCL_PIN);
gpios.sda = gpio_create(I2C_GP8302_2_SDA_PORT, I2C_GP8302_2_PIN);
gp8302[GP8302_2].i2c = i2c_create(gpios, 0);
}
BOOL gp8302_detection(void)
{
BOOL res = FALSE;
if (GPIO_READ(I2C_GP8302_1_DETECTION_PORT, I2C_GP8302_1_DETECTION_PIN) == 0)
{
res = TRUE;
}
else
{
return FALSE;
}
if (GPIO_READ(I2C_GP8302_2_DETECTION_PORT, I2C_GP8302_2_DETECTION_PIN) == 0)
{
res = TRUE;
}
else
{
return FALSE;
}
return res;
}
void gp8302_output(gp8302_number_e no, uint16_t pressure)
{
uint16_t hi = ((pressure >> 8) << 4) + ((uint8_t)pressure >> 4);
uint8_t lo = ((uint8_t)pressure) << 4;
pressure = (hi << 8) + lo;
i2c_t *p = gp8302[no].i2c;
p->interface.start(p);
p->interface.write_byte(p, 0xb0);
p->interface.wait_ack(p);
p->interface.write_byte(p, 2);
p->interface.wait_ack(p);
p->interface.write_word(p, pressure);
p->interface.wait_ack(p);
p->interface.stop(p);
}

22
gp8302.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef __GP8302_H__
#define __GP8302_H__
#include "main.h"
#include "i2cs.h"
#include "lib.h"
typedef enum
{
GP8302_1,
GP8302_2,
GP8302_MAX,
} gp8302_number_e;
typedef struct
{
i2c_t *i2c;
} gp8302_t;
void gp8302_init(void);
BOOL gp8302_detection(void);
void gp8302_output(gp8302_number_e no, uint16_t pressure);
#endif

118
ntc_3950.c Normal file
View File

@ -0,0 +1,118 @@
/**
* @file ntc_3950.c
* @author xxx
* @date 2023-08-30 08:58:43
* @brief NTC的应用功能
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "ntc_3950.h"
#define CPU_VREF 2.5
#define NTC_VREF 2.5
#define TABLE_SIZE 185
#define NTC_SERIES_RESISTOR 200000 ///< 200K
#define TEMP_MIN -55
#define TEMP_MAX 129
const uint32_t _table[TABLE_SIZE] = {
8989000, 8242680, 7592960, 7021380, 6513750, // -55,-54,-53,-52,-51
6059060, 5648680, 5275800, 4935020, 4621990, 4333220, 4065840, 3817520, 3586310, 3370600, // -50,-49,-48,-47,-46,-45,-44,-43,-42,-41
3169000, 2980330, 2803600, 2637910, 2482470, 2336580, 2199620, 2071020, 1950230, 1836790, // -40,-39,-38,-37,-36,-35,-34,-33,-32,-31
1730230, 1630150, 1536140, 1447840, 1364900, 1287000, 1213820, 1145090, 1080530, 1019890, // -30,-29,-28,-27,-26,-25,-24,-23,-22,-21
962912, 909379, 859074, 811797, 767359, 725581, 686296, 649348, 614590, 581883, // -20,-19,-18,-17,-16,-15,-14,-13,-12,-11
551100, 522117, 494824, 469113, 444886, 422050, 400518, 380209, 361048, 342963, // -10,-9,-8,-7,-6,-5,-4,-3,-2,-1
326560, 309764, 294529, 280131, 266520, 253647, 241470, 229946, 219036, 208706, // 0,1, 2, 3,4,5,6,7,8,9
198920, 189647, 180857, 172523, 164618, 157118, 150000, 143243, 136827, 130731, // 10,11 ,12, 13,14,15,16,17,18,19
124940, 119435, 114202, 109225, 104491, 100000, 95699, 91617, 87731, 84028, // 20,21, 22, 23,24,25,26,27,28,29
80501, 77140, 73936, 70881, 67968, 65188, 62537, 60006, 57590, 55283, // 30,31, 32, 33,34,35,36,37,38,39
53080, 50976, 48965, 47044, 45207, 43451, 41771, 40165, 38628, 37157, // 40,41, 42, 43,34,35,36,37,38,39
35750, 34402, 33112, 31876, 30692, 29558, 28471, 27429, 26430, 25472, // 50,51, 52, 53,54,55,56,57,58,59
24554, 23672, 22827, 22016, 21237, 20489, 19771, 19082, 18420, 17784, // 60,61, 62, 63,64,65,66,67,68,69
17172, 16585, 16020, 15477, 14955, 14453, 13970, 13505, 13058, 12628, // 70,71, 72, 73,74,75,76,77,78,79
12213, 11815, 11431, 11061, 10705, 10362, 10031, 9712, 9405, 9110, // 80,81, 82, 83,84,85,86,87,88,89
8824, 8549, 8284, 8028, 7782, 7544, 7314, 7093, 6879, 6673, // 90,91, 92, 93,94,95,96,97,98,99
6474, 6281, 6096, 5916, 5743, 5576, 5415, 5259, 5108, 4963, // 101,102, 103,104,105,106,107,108,109
4822, 4687, 4555, 4428, 4306, 4187, 4073, 3962, 3855, 3751, // 111,112, 113,114,115,116,117,118,119
3651, 3555, 3461, 3371, 3283, 3199, 3100, 3099, 2899, 2799, // 121,122, 123,124,125,126,127,128,129
};
/**
* @brief
* @param {uint32_t} *list
* @param {uint32_t} rt
* @return {*}
* @note
*/
static uint8_t ntc_lookup(const uint32_t *list, uint32_t rt)
{
uint8_t middle = 0;
uint8_t indexL = 0;
uint8_t indexR = TABLE_SIZE - 1;
if (rt >= *(list + 0))
return 0;
if (rt <= *(list + TABLE_SIZE - 1))
return TABLE_SIZE - 1;
while ((indexR - indexL) > 1)
{
middle = (indexL + indexR) >> 1;
if (rt == *(list + middle))
return middle;
else if (rt > *(list + middle))
indexR = middle;
else if (rt < *(list + middle))
indexL = middle;
}
return indexL;
}
/**
* @brief 0.1
* @param {uint16_t} adc采集值
* @return {float32_u}
* @note
*/
float32_u ntc_get_temp(uint16_t adc)
{
uint8_t index = 0;
int16_t data = 0;
int16_t t = 0;
int16_t result = 0;
uint32_t rt = 0;
const int16_t base = TEMP_MIN * 10;
float32_u res;
res.f = TEMP_MIN;
/**
* ad = (4095*rt)/(rt+10000)
*
* rt = (ad*NTC_SERIES_RESISTOR*CPU_VREF)/(NTC_VREF*4095-CPU_VREF*ad)
*/
rt = (adc * NTC_SERIES_RESISTOR * CPU_VREF) / (NTC_VREF * 4095 - CPU_VREF * adc);
index = ntc_lookup(_table, rt);
if (rt >= _table[0])
return res;
if (rt <= *(_table + TABLE_SIZE - 1))
{
result = (TABLE_SIZE - 1) * 10 + base;
}
else
{
data = _table[index] - _table[index + 1];
t = 10 * (_table[index] - rt) / data;
result = base + index * 10 + t;
}
res.f = result / 10.0;
return res;
}
// 判断传感器是否故障
BOOL ntc_is_fault_temp(float32 temp)
{
if (temp < TEMP_MIN || temp > TEMP_MAX)
{
return TRUE;
}
return FALSE;
}

15
ntc_3950.h Normal file
View File

@ -0,0 +1,15 @@
/**
* @file ntc_3950.h
* @author xxx
* @date 2023-08-30 14:05:55
* @brief ntc_3950.h
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __NTC_B3950_H__
#define __NTC_B3950_H__
#include "main.h"
extern float32_u ntc_get_temp(uint16_t adc); ///< 获取温度值
extern BOOL ntc_is_fault_temp(float32 temp); ///< 判断传感器是否故障
#endif ///< __NTC_B3950_H__

203
pt100.c Normal file
View File

@ -0,0 +1,203 @@
#include "pt100.h"
#pragma pack(1)
typedef struct
{
uint8_t address; // 从机地址
uint8_t code; // 功能码
uint16_t reg_address; // 寄存器地址
uint16_t reg_num; // 寄存器数量
uint16_t crc;
} pt100_data_t;
#pragma pack()
extern uart_t *uarts[UART_NUM_MAX];
static pt100_t handle;
float32 pt100_tempture[PT100_DATA_CHANNEL_NUM];
/* CRC low byte table */
static const unsigned char auchCRCLo[] =
{
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40};
/* CRC high byte table */
static const unsigned char auchCRCHi[] =
{
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};
/* Public functions ----------------------------------------------------------*/
/**
* @brief Calculate Modbus CRC16
* @param puchMsg: Data to calculate CRC
* @param usMsgLen: Data length
* @param puchCRCHi: High byte of CRC value
* @param puchCRCLo: Low byte of CRC value
* @note Send the low byte first
* @retval None
*/
void GetModbusCRC16(unsigned char *puchMsg, unsigned short usMsgLen,
unsigned char *puchCRCLo, unsigned char *puchCRCHi)
{
unsigned char uchCRCLo = 0xFF;
unsigned char uchCRCHi = 0xFF;
unsigned short uIndex = 0;
while (usMsgLen--)
{
uIndex = (unsigned char)(uchCRCHi ^ *puchMsg++);
uchCRCHi = (unsigned char)(uchCRCLo ^ auchCRCHi[uIndex]);
uchCRCLo = (unsigned char)(auchCRCLo[uIndex]);
}
*puchCRCLo = uchCRCHi;
*puchCRCHi = uchCRCLo;
}
static void pt100_rx_cb(uint8_t uart_index, uint8_t *data, uint16_t len)
{
uart_t *h = handle.huart;
if (h != NULL)
{
if (h->uart_index == uart_index)
{
if ((h->rx_sta & 0x8000) == 0) // 接收未完成
{
handle.ctx_recv_buf[h->rx_sta & 0X3FFF] = h->rxbuf[0];
h->rx_sta++;
if (h->rx_sta > (PT100_MODBUS_RECV_LENGTH - 1))
h->rx_sta = 0; // 接收数据错误,重新开始接收
}
}
}
}
static void pt100_uart_init(void)
{
if (uarts[PT100_RS485_PORT] == NULL)
{
uarts[PT100_RS485_PORT] = uart_create(USART4, FALSE, 1, pt100_rx_cb, FALSE, 0, NULL);
uarts[PT100_RS485_PORT]->uart_index = PT100_RS485_PORT;
}
}
void pt100_init(send_data_cb_t cb)
{
handle.send_data_cb = cb;
pt100_uart_init();
handle.huart = uarts[PT100_RS485_PORT];
DBG_ASSERT(handle.huart != NULL __DBG_LINE);
GPIO_RESET(RS485_EN2_GPIO_Port, RS485_EN2_Pin);
uart_recv_en(handle.huart);
handle.idel_flag = false;
osel_memset((uint8_t *)pt100_tempture, 0, sizeof(float32) * PT100_DATA_CHANNEL_NUM);
}
void pt100_process(void)
{
uart_t *h = handle.huart;
DBG_ASSERT(h != NULL __DBG_LINE);
pt100_data_t data;
data.address = 0x01;
data.code = 0x04;
data.reg_address = 0x0000;
data.reg_address = S2B_UINT16(data.reg_address);
data.reg_num = PT100_DATA_CHANNEL_NUM;
data.reg_num = S2B_UINT16(data.reg_num);
GetModbusCRC16((uint8_t *)&data, sizeof(pt100_data_t) - 2, (uint8_t *)&data.crc, (uint8_t *)&data.crc + 1);
h->rx_sta = 0;
handle.send_data_cb((uart_num_e)h->uart_index, (uint8_t *)&data, sizeof(pt100_data_t));
}
void pt100_data_deal(void)
{
uart_t *h = handle.huart;
uint8_t *p = handle.ctx_recv_buf;
uint8_t offset = 0;
uint16_t crc = 0, crc1 = 0;
uint16_t length = h->rx_sta;
uint16_t pt100_data[PT100_DATA_CHANNEL_NUM];
uint8_t pt100_data_length = 0;
if (h->rx_sta == 0)
{
return; // 未收到数据切换到下一个设备
}
h->rx_sta |= 0x8000; // 暂停串口接收数据20ms预留了充足的接收时间
if (p[offset] == 0x01 && p[++offset] == 0x04 && length > 4)
{
offset++;
// CRC校验
GetModbusCRC16(p, length - 2, (uint8_t *)&crc, (uint8_t *)&crc + 1);
osel_memcpy((uint8_t *)&crc1, p + length - 2, 2);
if (crc == crc1)
{
pt100_data_length = p[offset];
offset++; // 偏移过长度
osel_memcpy((uint8_t *)pt100_data, p + offset, pt100_data_length);
for (uint8_t i = 0; i < PT100_DATA_CHANNEL_NUM; i++)
{
pt100_data[i] = B2S_UINT16(pt100_data[i]);
if (pt100_data[i] != 0xffff)
{
pt100_tempture[i] = (float32)pt100_data[i] / 10;
}
else
{
pt100_tempture[i] = 129;
}
}
}
}
}

28
pt100.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef __PT100_H__
#define __PT100_H__
#include "board.h"
#include "agile_modbus.h"
#define PT100_RS485_PORT UART_NUM_3
#define PT100_SLAVER_ADDR 1U // 从机地址
#define PT100_DATA_CHANNEL_NUM 3U // 通道数
#define PT100_MODBUS_RECV_LENGTH 30U // 接收缓冲区大小
#define PT100_MODBUS_SEND_LENGTH 30U // modbus最大数据长度
typedef struct
{
BOOL idel_flag; // 通过这个标识位来判断是否需要初始化modbus
uart_t *huart;
float32_t temperature; // 温度
agile_modbus_rtu_t ctx_rtu;
uint8_t ctx_send_buf[PT100_MODBUS_SEND_LENGTH];
uint8_t ctx_recv_buf[PT100_MODBUS_RECV_LENGTH]; // 公用一个接收缓冲区
send_data_cb_t send_data_cb; // 发送数据回调函数,外部传入
} pt100_t;
extern float32 pt100_tempture[PT100_DATA_CHANNEL_NUM];
void pt100_init(send_data_cb_t cb);
void pt100_process(void);
void pt100_data_deal(void);
#endif // __PT100_H__

560
rtc_rx8010.c Normal file
View File

@ -0,0 +1,560 @@
/**
* @file rtc_rx8010.c
* @author xxx
* @date 2023-08-30 08:58:43
* @brief RTC芯片RX8010的应用功能
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#include "rtc_rx8010.h"
#include "i2cs.h"
#include "delay.h"
#define RTC_RX8010_SDA_PORT RTC_SDA_GPIO_Port
#define RTC_RX8010_SDA_PIN RTC_SDA_Pin
#define RTC_RX8010_SCL_PORT RTC_SCL_GPIO_Port
#define RTC_RX8010_SCL_PIN RTC_SCL_Pin
static i2c_t *rtc;
static TIM_TypeDef *_timer_us;
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
/* sec, min, hour, week, day, month, year */
// static uint8_t calendar[7] = {0, 0, 0, 1, 29, 2, 98};
/**
* @brief RTC芯片的指定地址读取一个字节数据
* @param {uint8_t} *read_buf
* @param {uint8_t} addr
* @return {*}
*/
static BOOL rtc_read_byte(uint8_t *read_buf, uint8_t addr)
{
uint8_t *p = read_buf;
/* 发送起始信号 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送读地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 重新发送起始信号。前面的代码的目的向RTC传送地址下面开始读取数据 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 读取数据 */
*p = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief RTC芯片的指定地址读取若干数据
* @param {uint8_t} *read_buf
* @param {uint8_t} addr
* @param {int} size
* @return {*}
*/
static BOOL rtc_read_bytes(uint8_t *read_buf, uint8_t addr, int size)
{
int i = 0;
/* 发送起始信号 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 此处是写方向,因为要发送读地址 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送读地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 重新发送起始信号。前面的代码的目的向RTC传送地址下面开始读取数据 */
rtc->interface.start(rtc);
/* 发送从机地址 + 读写方向 */
rtc->interface.write_byte(rtc, RTC_RD_ADDR); /* 此处是读方向,因为要开始读数据了 */
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 循环读取数据RTC芯片地址自动自增 */
for (i = 0; i < size; i++)
{
/* 每读完1个字节后需要发送Ack 最后一个字节需要发Nack */
if (i != (size - 1))
{
read_buf[i] = rtc->interface.read_byte(rtc, TRUE); /* 读1个字节 */
}
else
{
read_buf[i] = rtc->interface.read_byte(rtc, FALSE); /* 读1个字节 */
}
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief RTC芯片的指定地址写入一个数据
* @param {uint8_t} data
* @param {uint8_t} addr
* @return {*}
* @note
*/
static BOOL rtc_write_byte(uint8_t data, uint8_t addr)
{
int retry = 0;
/* 尝试与RTC芯片建立I2C通讯 */
for (retry = 0; retry < 100; retry++)
{
rtc->interface.start(rtc); /* 发送起始信号 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
if (rtc->interface.wait_ack(rtc) == TRUE)
{
break;
}
}
if (retry == 100)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送起始写地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 写入数据 */
rtc->interface.write_byte(rtc, data);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief RTC芯片的指定地址写入若干数据
* @param {uint8_t} *write_buf
* @param {uint8_t} addr
* @param {int} size
* @return {*}
* @note
*/
static BOOL rtc_write_bytes(uint8_t *write_buf, uint8_t addr, int size)
{
int i = 0;
int retry = 0;
for (i = 0; i < size; i++)
{
if (i == 0)
{
/* 尝试与RTC芯片建立I2C通讯 */
for (retry = 0; retry < 100; retry++)
{
rtc->interface.start(rtc); /* 发送起始信号 */
rtc->interface.write_byte(rtc, RTC_WR_ADDR); /* 发送从机地址 + 读写方向 */
if (rtc->interface.wait_ack(rtc) == TRUE)
{
break;
}
}
if (retry == 100)
{
rtc->interface.stop(rtc);
return FALSE;
}
/* 发送起始写地址 */
rtc->interface.write_byte(rtc, addr);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
}
/* 循环写入数据RTC芯片地址自动自增 */
rtc->interface.write_byte(rtc, write_buf[i]);
if (rtc->interface.wait_ack(rtc) != TRUE)
{
rtc->interface.stop(rtc);
return FALSE;
}
}
/* 命令执行成功发送I2C总线停止信号 */
rtc->interface.stop(rtc);
return TRUE;
}
/**
* @brief RTC芯片RTC响应
* @return {*}
* @note
*/
static void rtc_dummy_read(void)
{
rtc->interface.start(rtc);
rtc->interface.write_byte(rtc, RTC_WR_ADDR);
rtc->interface.write_byte(rtc, 0x20);
rtc->interface.start(rtc);
rtc->interface.write_byte(rtc, RTC_RD_ADDR);
rtc->interface.read_byte(rtc, FALSE);
rtc->interface.stop(rtc);
}
/**
* @brief VLF0x1e bit[1]
* @return {uint8_t} 0 = VLF位为01 = VLF位为1
* @note
*/
static uint8_t rtc_check_vlf(void)
{
uint8_t flag_register = 1;
uint8_t vlf = 0;
rtc_read_byte(&flag_register, RTC_FLAG_ADDR);
vlf = (flag_register & 0x02);
if (vlf == 0)
{
return 0;
}
else
{
return 1;
}
}
/**
* @brief VLF位清除0x1e bit[1]
* @return {uint8_t} 0 = 1 = 2 =
*/
static uint8_t rtc_wait_vlf_clear(void)
{
uint8_t ret = 1;
uint8_t i = 0;
uint8_t vlf;
for (i = 0; i < 10; i++)
{
vlf = rtc_check_vlf();
if (vlf == 0)
{
ret = ((i > 0) ? 0 : 2);
return ret;
}
/* 清除VLF */
rtc_write_byte(0, RTC_FLAG_ADDR);
}
return ret;
}
/**
* @brief
* @return {BOOL} FALSE = TRUE =
*/
static BOOL rtc_soft_reset(void)
{
BOOL ret = FALSE;
ret = rtc_write_byte(0x00, 0x1f);
ret = rtc_write_byte(0x80, 0x1f);
ret = rtc_write_byte(0xd3, 0x60);
ret = rtc_write_byte(0x03, 0x66);
ret = rtc_write_byte(0x02, 0x6b);
ret = rtc_write_byte(0x01, 0x6b);
if (ret == 0)
{
_delay_us(2000);
}
return ret;
}
/**
* @brief
* @return {BOOL} TRUE = FALSE =
*/
static BOOL rtc_clock_reginit(void)
{
BOOL ret = FALSE;
/* set reserve register */
ret = rtc_write_byte(RTC_REG17_DATA, RTC_REG17_ADDR);
ret = rtc_write_byte(RTC_REG30_DATA, RTC_REG30_ADDR);
ret = rtc_write_byte(RTC_REG31_DATA, RTC_REG31_ADDR);
ret = rtc_write_byte(RTC_IRQ_DATA, RTC_IRQ_ADDR);
/* write 0x04 to reg_0x1d */
ret = rtc_write_byte(0x04, 0x1d);
/* write 0x00 to reg_0x1e */
ret = rtc_write_byte(0x00, 0x1e);
/* stop clock */
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
/* set the present time */
// ret = rtc_write_bytes(calendar, RTC_CLOCK_ADDR, sizeof(calendar));
/* start clock */
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
return ret;
}
/**
* @brief RTC芯片初始化
* @return {BOOL} TRUE = FALSE =
* @note
*/
BOOL rtc_init(TIM_TypeDef *timer_us)
{
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios;
int ret = 1;
gpios.scl = gpio_create(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
gpios.sda = gpio_create(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
rtc = i2c_create(gpios, 10);
rtc_dummy_read();
/* wait for VLF bit clear */
ret = rtc_wait_vlf_clear();
if (ret == 0)
{
/* software reset */
ret = rtc_soft_reset();
if (ret == FALSE)
{
return FALSE;
}
}
else if (ret == 1)
{
return FALSE;
}
/* register initialize */
return rtc_clock_reginit();
}
/**
* @brief RTC芯片反初始化
* @return {*}
* @note
*/
BOOL rtc_dinit(void)
{
GPIO_SET_ANALOG(RTC_RX8010_SCL_PORT, RTC_RX8010_SCL_PIN);
GPIO_SET_ANALOG(RTC_RX8010_SDA_PORT, RTC_RX8010_SDA_PIN);
return TRUE;
}
/**
* @brief RTC芯片读取时间
* @param {uint8_t} *read_buf -
* @return {BOOL} TRUE = FALSE =
* @note
*/
BOOL rtc_get_clock_time(uint8_t *read_buf)
{
return rtc_read_bytes(read_buf, RTC_CLOCK_ADDR, 7);
}
/**
* @brief RTC芯片写入时间
* @param {rtc_date} *data -
* @return {BOOL} TRUE = FALSE =
* @note
*/
BOOL rtc_set_clock_time(rtc_date *data)
{
BOOL ret = FALSE;
uint8_t tmp[7];
tmp[0] = data->second;
tmp[1] = data->minute;
tmp[2] = data->hour;
tmp[3] = data->weekday;
tmp[4] = data->day;
tmp[5] = data->month;
tmp[6] = data->year;
tmp[3] = (rtc_week_e)tmp[3]; // 改成星期几
/* stop clock */
ret = rtc_write_byte(0x40, RTC_CONTROL_ADDR);
/* set the present time */
ret = rtc_write_bytes(tmp, RTC_CLOCK_ADDR, sizeof(tmp));
/* start clock */
ret = rtc_write_byte(0x00, RTC_CONTROL_ADDR);
return ret;
}
/**
* RTC
*
* RTC设备中获取当前的日期和时间197011
* RTC设备中获取时间0
*
* @return 1970110
*/
uint32_t rtc_timestamp(void)
{
BOOL ret = FALSE;
uint8_t tmp[7];
rtc_date_t date;
rtc_time_t time;
ret = rtc_get_clock_time(tmp);
if (ret == FALSE)
{
return 0;
}
date.year = hex_format_dec(tmp[6]);
date.month = hex_format_dec(tmp[5]);
date.day = hex_format_dec(tmp[4]);
time.hour = hex_format_dec(tmp[2]);
time.minute = hex_format_dec(tmp[1]);
time.second = hex_format_dec(tmp[0]);
return time2stamp(&date, &time);
}
/**
* @brief
* @param {uint8_t} *weekday
* @return {*}
* @note
*/
void rtc_weekday_convert(uint8_t *weekday)
{
switch (*weekday)
{
case 1:
*weekday = MON;
break;
case 2:
*weekday = TUE;
break;
case 3:
*weekday = WED;
break;
case 4:
*weekday = THUR;
break;
case 5:
*weekday = FRI;
break;
case 6:
*weekday = SAT;
break;
case 7:
*weekday = SUN;
break;
default:
*weekday = 0;
break;
}
}
/**
* @brief
* @param {uint8_t} *weekday
* @return {*}
* @note
*/
void rtc_weekday_rconvert(uint8_t *weekday)
{
switch (*weekday)
{
case MON:
*weekday = 1;
break;
case TUE:
*weekday = 2;
break;
case WED:
*weekday = 3;
break;
case THUR:
*weekday = 4;
break;
case FRI:
*weekday = 5;
break;
case SAT:
*weekday = 6;
break;
case SUN:
*weekday = 7;
break;
default:
*weekday = 0;
break;
}
}

99
rtc_rx8010.h Normal file
View File

@ -0,0 +1,99 @@
/**
* @file rtc_rx8010.h
* @author xxx
* @date 2023-08-30 14:05:55
* @brief rtc_rx8010.h
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
*/
#ifndef __RTC_RX8010_H__
#define __RTC_RX8010_H__
#include "main.h"
#define RTC_DEVICE_ADDR 0x32
#define RTC_WR_ADDR ((RTC_DEVICE_ADDR << 1) | 0)
#define RTC_RD_ADDR ((RTC_DEVICE_ADDR << 1) | 1)
#define RTC_FLAG_ADDR 0x1e
#define RTC_CLOCK_ADDR 0x10
#define RTC_CONTROL_ADDR 0x1f
#define RTC_REG17_ADDR 0x17
#define RTC_REG17_DATA 0xd8
#define RTC_REG30_ADDR 0x30
#define RTC_REG30_DATA 0x00
#define RTC_REG31_ADDR 0x31
#define RTC_REG31_DATA 0x08
#define RTC_IRQ_ADDR 0x32
#define RTC_IRQ_DATA 0x00
typedef enum
{
SUN = BIT0,
MON = BIT1,
TUE = BIT2,
WED = BIT3,
THUR = BIT4,
FRI = BIT5,
SAT = BIT6
} rtc_week_e; ///< 星期码
typedef struct
{
uint8_t year; ///< 7 bit - 1 63
uint8_t month; ///< 4 bit
uint8_t day; ///< 5 bit
uint8_t weekday; ///< rtc_week_e
uint8_t hour; ///< 5 bit
uint8_t minute; ///< 6 bit
uint8_t second; ///< 6 bit
} rtc_date;
/**
* @brief Initializes the RTC module.
* @return TRUE if the initialization is successful, FALSE otherwise.
*/
extern BOOL rtc_init(TIM_TypeDef *timer_us);
/**
* @brief Deinitializes the RTC module.
* @return TRUE if the deinitialization is successful, FALSE otherwise.
*/
extern BOOL rtc_dinit(void);
/**
* @brief Retrieves the current clock time from the RTC module.
* @param read_buf Pointer to the buffer to store the clock time.
* @return TRUE if the clock time is successfully retrieved, FALSE otherwise.
*/
extern BOOL rtc_get_clock_time(uint8_t *read_buf);
/**
* @brief Sets the clock time in the RTC module.
* @param data Pointer to the RTC date structure containing the new clock time.
* @return TRUE if the clock time is successfully set, FALSE otherwise.
*/
extern BOOL rtc_set_clock_time(rtc_date *data);
/**
* @brief Retrieves the current alarm time from the RTC module.
* @param read_buf Pointer to the buffer to store the alarm time.
* @return TRUE if the alarm time is successfully retrieved, FALSE otherwise.
*/
extern uint32_t rtc_timestamp(void);
/**
* @brief Converts the weekday value to a human-readable format.
* @param weekday Pointer to the weekday value to be converted.
*/
extern void rtc_weekday_convert(uint8_t *weekday);
/**
* @brief Converts the weekday value from a human-readable format to the RTC format.
* @param weekday Pointer to the weekday value to be converted.
*/
extern void rtc_weekday_rconvert(uint8_t *weekday);
#endif ///< !__RTC_RX8010_H__

181
sht40.c Normal file
View File

@ -0,0 +1,181 @@
#include "sht40.h"
#include "i2cs.h"
#include "delay.h"
#define SHT40_SDA_PORT I2C1_SDA_GPIO_Port
#define SHT40_SDA_PIN I2C1_SDA_Pin
#define SHT40_SCL_PORT I2C1_SCL_GPIO_Port
#define SHT40_SCL_PIN I2C1_SCL_Pin
#define SHT40_I2C_ADDRESS 0x44
#define SHT40_MEASURE_CMD 0xFD // 2*8-bit T-data:8-bit CRC:2*8-bit RH-data: 8-bit CRC
static i2c_t *_sht40_i2c;
static TIM_TypeDef *_timer_us;
static uint8_t crc8(uint8_t *data, uint8_t len);
static void _delay_us(uint32_t us)
{
if (_timer_us != NULL)
{
delay_hardware_us(_timer_us, us);
}
else
{
delay_us(us);
}
}
void sht40_test(void)
{
float32 temperature = 0;
float32 humidity = 0;
sht40_read(&temperature, &humidity);
__NOP();
}
/**
* @brief SHT40
*
* SHT40 I2C GPIO I2C
*
* sht40_i2c SHT40
*/
void sht40_init(TIM_TypeDef *timer_us)
{
DBG_ASSERT(timer_us != NULL __DBG_LINE);
if (timer_us != NULL)
{
_timer_us = timer_us;
ENABLE_TIM_COUNT(_timer_us);
}
i2c_gpio_group_t gpios;
gpios.scl = gpio_create(SHT40_SCL_PORT, SHT40_SCL_PIN);
gpios.sda = gpio_create(SHT40_SDA_PORT, SHT40_SDA_PIN);
_sht40_i2c = i2c_create(gpios, 10);
DBG_ASSERT(_sht40_i2c != NULL __DBG_LINE);
// sht40_test(); // 测试 SHT40
}
/**
* @brief SHT40
*
* SHT40 湿便湿
*
*
*/
void sht40_dinit(void)
{
GPIO_SET_ANALOG(SHT40_SDA_PORT, SHT40_SDA_PIN);
GPIO_SET_ANALOG(SHT40_SCL_PORT, SHT40_SCL_PIN);
}
/**
* @brief 湿
*
* 湿湿
*
* @param temperature
* @param humidity 湿
*/
BOOL sht40_read(float32 *temperature, float32 *humidity)
{
uint8_t data[6];
osel_memset(data, 0, ARRAY_LEN(data));
// 发送开始信号
_sht40_i2c->interface.start(_sht40_i2c);
// 发送写入地址命令
_sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_I2C_ADDRESS << 1);
// 等待写入地址命令响应
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{
return FALSE;
}
// 发送测量命令
_sht40_i2c->interface.write_byte(_sht40_i2c, SHT40_MEASURE_CMD);
// 等待测量命令响应
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{
return FALSE;
}
// 停止I2C总线
_sht40_i2c->interface.stop(_sht40_i2c);
_delay_us(10000); // 根据 SHT40 数据手册,等待至少 10ms
// 发送开始信号
_sht40_i2c->interface.start(_sht40_i2c);
// 发送写入地址命令
_sht40_i2c->interface.write_byte(_sht40_i2c, (SHT40_I2C_ADDRESS << 1) | 1);
// 等待写入地址命令响应
if (_sht40_i2c->interface.wait_ack(_sht40_i2c) == FALSE)
{
return FALSE;
}
for (uint8_t i = 0; i < ARRAY_LEN(data); i++)
{
if (i == 5)
{
data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, FALSE);
}
else
{
data[i] = _sht40_i2c->interface.read_byte(_sht40_i2c, TRUE);
}
}
// 停止I2C总线
_sht40_i2c->interface.stop(_sht40_i2c);
*temperature = 0;
*humidity = 0;
if (crc8(&data[0], 2) != data[2] || crc8(&data[3], 2) != data[5])
{
return FALSE;
}
else
{
*temperature = (float32)((uint16_t)data[0] << 8 | data[1]) * 175 / 65535 - 45;
*humidity = (float32)((uint16_t)data[3] << 8 | data[4]) * 125 / 65535 - 6;
if (*humidity > 100)
{
*humidity = 100;
}
if (*humidity < 0)
{
*humidity = 0;
}
return TRUE;
}
}
/**
* @brief crc8校验函数 x^8 + x^5 + x^4 + 1
* @param data
* @param len
* @retval
* @note SHT3温湿度传感器的数据校验
*/
static uint8_t crc8(uint8_t *data, uint8_t len)
{
const uint8_t polynomial = 0x31;
uint8_t crc = 0xFF;
int i, j;
for (i = 0; i < len; ++i)
{
crc ^= *data++;
for (j = 0; j < 8; ++j)
{
crc = (crc & 0x80) ? (crc << 1) ^ polynomial : (crc << 1);
}
}
return crc;
}

9
sht40.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef __SHT40_H
#define __SHT40_H
#include "main.h"
void sht40_init(TIM_TypeDef *timer_us); ///< 初始化 SHT40 传感器
void sht40_dinit(void); ///< 反初始化 SHT40 传感器
BOOL sht40_read(float32 *temperature, float32 *humidity); ///< 读取温湿度传感器数据
#endif ///< !__SHT40_H

1011
ssd1306_oled.c Normal file

File diff suppressed because it is too large Load Diff

80
ssd1306_oled.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef __SSD1306_OLED_H
#define __SSD1306_OLED_H
#include "main.h"
// OLED引脚定义
#define SSD1306_SDA_PORT OLED_SDA_GPIO_Port
#define SSD1306_SDA_PIN OLED_SDA_Pin
#define SSD1306_SCK_PORT OLDE_SCK_GPIO_Port
#define SSD1306_SCK_PIN OLDE_SCK_Pin
// I2C地址
#define SSD1306_I2C_ADDRESS 0x78
// OLED显示参数
#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
// OLED颜色
#define SSD1306_WHITE 1
#define SSD1306_BLACK 0
// OLED命令定义
#define SSD1306_CMD_DISPLAY_OFF 0xAE
#define SSD1306_CMD_DISPLAY_ON 0xAF
#define SSD1306_CMD_SET_CONTRAST 0x81
#define SSD1306_CMD_DISPLAY_ALL_ON_RESUME 0xA4
#define SSD1306_CMD_DISPLAY_ALL_ON 0xA5
#define SSD1306_CMD_NORMAL_DISPLAY 0xA6
#define SSD1306_CMD_INVERT_DISPLAY 0xA7
#define SSD1306_CMD_SET_DISPLAY_OFFSET 0xD3
#define SSD1306_CMD_SET_COM_PINS 0xDA
#define SSD1306_CMD_SET_VCOM_DETECT 0xDB
#define SSD1306_CMD_SET_DISPLAY_CLOCK_DIV 0xD5
#define SSD1306_CMD_SET_PRECHARGE 0xD9
#define SSD1306_CMD_SET_MULTIPLEX 0xA8
#define SSD1306_CMD_SET_LOW_COLUMN 0x00
#define SSD1306_CMD_SET_HIGH_COLUMN 0x10
#define SSD1306_CMD_SET_START_LINE 0x40
#define SSD1306_CMD_MEMORY_MODE 0x20
#define SSD1306_CMD_COLUMN_ADDR 0x21
#define SSD1306_CMD_PAGE_ADDR 0x22
#define SSD1306_CMD_COM_SCAN_INC 0xC0
#define SSD1306_CMD_COM_SCAN_DEC 0xC8
#define SSD1306_CMD_SEG_REMAP 0xA0
#define SSD1306_CMD_CHARGE_PUMP 0x8D
#define SSD1306_CMD_SET_DC_DC_ENABLE 0x14
#define SDA_OUT() \
{ \
GPIO_SET_OUTPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
}
#define SDA_IN() \
{ \
GPIO_SET_INPUT(SSD1306_SDA_PORT, SSD1306_SDA_PIN); \
}
// 函数声明
void ssd1306_init(void);
void ssd1306_logo(void);
void ssd1306_display_on(void);
void ssd1306_display_off(void);
void ssd1306_update_screen(void);
void ssd1306_fill(uint8_t color);
void ssd1306_clear(void);
void ssd1306_clear_buffer(void);
void ssd1306_draw_bmp(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, const uint8_t *bmp);
void ssd1306_f6x8_string(uint8_t x, uint8_t y, const uint8_t *ch);
void ssd1306_f6x8_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num);
void ssd1306_f6x8_string_number(uint8_t x, uint8_t y, const uint8_t *ch, uint8_t unit, float32 num);
void ssd1306_f8x16_string(uint8_t x, uint8_t y, const uint8_t *ch);
void ssd1306_f8x16_number(uint8_t x, uint8_t y, float32 num, uint8_t dot_num);
void ssd1306_draw_text_center(uint8_t y, const char *text);
void ssd1306_draw_progress_bar(uint8_t progress);
void ssd1306_fill_rect_angle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
void ssd1306_draw_rect_angle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color);
void ssd1306_draw_line(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t color);
void ssd1306_draw_pixel(uint8_t x, uint8_t y, uint8_t color);
#endif // __SSD1306_OLED_H

129
tca9555.c Normal file
View File

@ -0,0 +1,129 @@
#include "tca9555.h"
#include "i2cs.h"
#define I2C_MASTER_SCL_PORT I2C1_SCL_GPIO_Port
#define I2C_MASTER_SCL_PIN I2C1_SCL_Pin
#define I2C_MASTER_SDA_PORT I2C1_SDA_GPIO_Port
#define I2C_MASTER_SDA_PIN I2C1_SDA_Pin
static i2c_t *tca9555_i2c;
void tca9555_init(void)
{
i2c_gpio_group_t gpios;
gpios.scl = gpio_create(I2C_MASTER_SCL_PORT, I2C_MASTER_SCL_PIN);
gpios.sda = gpio_create(I2C_MASTER_SDA_PORT, I2C_MASTER_SDA_PIN);
tca9555_i2c = i2c_create(gpios, 0);
tca9555_register reg;
osel_memset((uint8_t *)&reg, 0, sizeof(tca9555_register));
tca9555_write_config(&reg);
osel_memset((uint8_t *)&reg, 0, sizeof(tca9555_register));
reg.port.p0.asint = 0;
reg.port.p1.asint = 0;
tca9555_write_output(&reg);
}
void tca9555_configure_input(tca9555_register *reg, uint8_t port, uint8_t pin)
{
if (port == 0)
{
reg->port.p0.asint |= (1 << pin); // 设置对应的引脚为输入
}
else if (port == 1)
{
reg->port.p1.asint |= (1 << pin); // 设置对应的引脚为输入
}
tca9555_write_config(reg);
}
uint8_t tca9555_read_single_register(tca9555_reg_t address)
{
uint8_t reg_data = 0; // 定义一个8位无符号字符型变量reg_data用于存储读取到的寄存器值
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, address);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, READ_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
reg_data = tca9555_i2c->interface.read_byte(tca9555_i2c, FALSE);
tca9555_i2c->interface.stop(tca9555_i2c);
return reg_data;
}
void tca9555_write_single_register(tca9555_reg_t address, uint8_t reg_val)
{
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, address);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_val);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.stop(tca9555_i2c);
}
void tca9555_read_struct(tca9555_register *reg, tca9555_reg_t reg_num)
{
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, READ_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
reg->port.p0.asint = tca9555_i2c->interface.read_byte(tca9555_i2c, TRUE);
reg->port.p1.asint = tca9555_i2c->interface.read_byte(tca9555_i2c, FALSE);
tca9555_i2c->interface.stop(tca9555_i2c);
}
void tca9555_write_struct(tca9555_register *reg, tca9555_reg_t reg_num)
{
uint8_t reg_data[2];
osel_memcpy(reg_data, (uint8_t *)reg, sizeof(tca9555_register));
tca9555_i2c->interface.start(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, WRITE_ADDRESS);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_num);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_data[0]);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.write_byte(tca9555_i2c, reg_data[1]);
tca9555_i2c->interface.wait_ack(tca9555_i2c);
tca9555_i2c->interface.stop(tca9555_i2c);
}
void tca9555_write_output(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_OUTPUT_REG0);
}
void tca9555_write_polarity(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_POLARITY_REG0);
}
void tca9555_write_config(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_CONFIG_REG0);
}
void tca9555_read_input(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_INPUT_REG0);
}
void tca9555_read_output(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_OUTPUT_REG0);
}
void tca9555_read_polarity(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_POLARITY_REG0);
}
void tca9555_read_config(tca9555_register *reg)
{
tca9555_write_struct(reg, TCA9555_CONFIG_REG0);
}

78
tca9555.h Normal file
View File

@ -0,0 +1,78 @@
#ifndef __TCA9555_H__
#define __TCA9555_H__
#include "main.h"
#include "lib.h"
#define TCA9555_ADDRESS 0x20 /*!< I2C Address */
/************************** I2C Registers *************************************/
typedef enum
{
TCA9555_INPUT_REG0 = 0x00, /*!< 输入状态寄存器 */
TCA9555_INPUT_REG1 = 0x01, /*!< 输入状态寄存器 */
TCA9555_OUTPUT_REG0 = 0x02, /*!< 输出寄存器以更改输出状态的位。设置为1时设置为高电平 */
TCA9555_OUTPUT_REG1 = 0x03, /*!< 输出寄存器以更改输出状态的位。设置为1时设置为高电平 */
TCA9555_POLARITY_REG0 = 0x04, /*!< 极性反转寄存器。位'1'在寄存器0x00上反转输入极性 */
TCA9555_POLARITY_REG1 = 0x05, /*!< 极性反转寄存器。位'1'在寄存器0x00上反转输入极性 */
TCA9555_CONFIG_REG0 = 0x06, /*!< 配置寄存器。位'1'设置为输入,位'0'设置为输出 */
TCA9555_CONFIG_REG1 = 0x07 /*!< 配置寄存器。位'1'设置为输入,位'0'设置为输出 */
} tca9555_reg_t;
#define CONFIG_INPUT_VAL 0xFF
#define CONFIG_OUTPUT_VAL 0x00
#define WRITE_ADDRESS ((TCA9555_ADDRESS << 1) | 0) /*!< I2C主设备写入 */
#define READ_ADDRESS ((TCA9555_ADDRESS << 1) | 1) /*!< I2C主设备读取 */
#define ACK_CHECK_EN 0x1 /*!< I2C主设备检查从设备ACK */
#define ACK_CHECK_DIS 0x0 /*!< I2C主设备不检查从设备ACK */
#define ACK_VAL 0x0 /*!< I2C从设备ACK值 */
#define NACK_VAL 0x1 /*!< I2C从设备NACK值 */
struct tca9555_sbit
{
uint8_t b0 : 1;
uint8_t b1 : 1;
uint8_t b2 : 1;
uint8_t b3 : 1;
uint8_t b4 : 1;
uint8_t b5 : 1;
uint8_t b6 : 1;
uint8_t b7 : 1;
};
union tca9555_uinputport
{
uint8_t asint; /*!< port data as unsigned integer */
struct tca9555_sbit bit; /*!< port data as separate bits */
};
struct tca9555_sregister
{
union tca9555_uinputport p0;
union tca9555_uinputport p1;
};
typedef union
{
uint16_t asint; /*!< register data as unsigned integer */
struct tca9555_sregister port; /*!< register data as separate ports */
} tca9555_register;
void tca9555_init(void); // 初始化i2c总线
void tca9555_configure_input(tca9555_register *reg, uint8_t port, uint8_t pin); // 配置输入
uint8_t tca9555_read_single_register(tca9555_reg_t address); // 读取单个寄存器
void tca9555_write_single_register(tca9555_reg_t address, uint8_t reg_val); // 写入单个寄存器
void tca9555_read_struct(tca9555_register *reg, tca9555_reg_t reg_num); // 读取结构体
void tca9555_write_struct(tca9555_register *reg, tca9555_reg_t reg_num); // 写入结构体
void tca9555_write_output(tca9555_register *reg);
void tca9555_write_polarity(tca9555_register *reg);
void tca9555_write_config(tca9555_register *reg);
void tca9555_read_input(tca9555_register *reg);
void tca9555_read_output(tca9555_register *reg);
void tca9555_read_polarity(tca9555_register *reg);
void tca9555_read_config(tca9555_register *reg);
#endif // __TCA9555_H__

368
tmc2240.c Normal file
View File

@ -0,0 +1,368 @@
#include "tmc2240.h"
tmc2240_t _tmc2240[TMC2240_MAX];
static void tmc2240_write(tmc2240_index_e index, uint8_t *data)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
tmc->spi->interface.u.normal.spi_send(tmc->spi, data[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
}
static void tmc2240_read(tmc2240_index_e index, uint8_t *wdata, uint8_t *rdata)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
__NOP();
__NOP();
__NOP();
tmc->spi->gpios.cs->reset(*tmc->spi->gpios.cs);
for (uint16_t i = 0; i < 5; i++)
{
rdata[i] = tmc->spi->interface.u.normal.spi_send(tmc->spi, wdata[i]);
}
tmc->spi->gpios.cs->set(*tmc->spi->gpios.cs);
}
static void tmc2240_reg_write(tmc2240_index_e index, uint8_t reg, uint32_t data)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
uint8_t wdata[5] = {0};
wdata[0] = TMC2240_HIGHT_BIT | reg;
wdata[1] = (data >> 24) & 0xFF;
wdata[2] = (data >> 16) & 0xFF;
wdata[3] = (data >> 8) & 0xFF;
wdata[4] = data & 0xFF;
tmc2240_write(index, wdata);
}
static uint32_t tmc2240_reg_read(tmc2240_index_e index, uint8_t reg)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
uint8_t wdata[5] = {0};
uint8_t rdata[5] = {0};
wdata[0] = reg;
tmc2240_read(index, wdata, rdata);
return (rdata[1] << 24) | (rdata[2] << 16) | (rdata[3] << 8) | rdata[4];
}
/**
* @brief TMC2240步进电机驱动器
*
* TMC2240步进电机驱动器的各种参数线
*
* @param index TMC2240步进电机驱动器的索引
*/
static void tmc2240_config_write(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
tmc->config.gconf.data = 0x00000000;
tmc->config.chopconf.data = 0x00410153;
tmc->config.chopconf.bits.mres = TMC2240_MRES_8;
tmc->config.drvconf.data = 0x00000021;
tmc->config.global_scaler.data = 0x00000000;
tmc->config.ihold_irun.bits.ihold = 31;
tmc->config.ihold_irun.bits.irun = 31;
tmc->config.ihold_irun.bits.iholddelay = 0;
tmc->config.ihold_irun.bits.irundelay = 0;
tmc->config.pwmconf.data = 0xC44C261E;
tmc->config.gstat.data = 0x00000007;
tmc2240_reg_write(index, TMC2240_GCONF, tmc->config.gconf.data);
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
tmc2240_reg_write(index, TMC2240_DRV_CONF, tmc->config.drvconf.data);
tmc2240_reg_write(index, TMC2240_GLOBAL_SCALER, tmc->config.global_scaler.data);
tmc2240_reg_write(index, TMC2240_IHOLD_IRUN, tmc->config.ihold_irun.data);
tmc2240_reg_write(index, TMC2240_PWMCONF, tmc->config.pwmconf.data);
tmc2240_reg_write(index, TMC2240_GSTAT, tmc->config.gstat.data);
}
static void _tmc2240_motor_update(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
switch (tmc->config.chopconf.bits.mres)
{
case TMC2240_MRES_256:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 256;
break;
case TMC2240_MRES_128:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 128;
break;
case TMC2240_MRES_64:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 64;
break;
case TMC2240_MRES_32:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 32;
break;
case TMC2240_MRES_16:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 16;
break;
case TMC2240_MRES_8:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 8;
break;
case TMC2240_MRES_4:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 4;
break;
case TMC2240_MRES_2:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE / 2;
break;
case TMC2240_MRES_1:
tmc->motor.step_angle = MOTOR_42_STEP_ANGLE;
break;
default:
break;
}
tmc->motor.circle_pulse = 360 / tmc->motor.step_angle;
}
static void _tmc2240_enable(tmc2240_index_e index, BOOL enable)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
BOOL state = tmc->en->read(*tmc->en) == 0 ? TRUE : FALSE;
if (state == enable)
{
return;
}
if (enable == TRUE)
{
PWM_START(tmc->timer, tmc->time_ch);
tmc->en->reset(*tmc->en);
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
}
else
{
PWM_STOP(tmc->timer, tmc->time_ch);
tmc->en->set(*tmc->en);
chopconf_u chopconf;
osel_memset((uint8_t *)&chopconf, 0, sizeof(chopconf_u));
chopconf.bits.mres = TMC2240_MRES_1;
tmc2240_reg_write(index, TMC2240_CHOPCONF, chopconf.data);
}
}
static void _tmc2240_direction(tmc2240_index_e index, tmc2240_direction_e dir)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (dir == TMC2240_FORWARD)
{
tmc->dir->reset(*tmc->dir);
}
else
{
tmc->dir->set(*tmc->dir);
}
}
void tmc2240_init(tmc2240_index_e index, SPI_TypeDef *SPIx, TIM_TypeDef *timer, uint32_t time_ch, spi_gpio_group_t *gpios)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
osel_memset((uint8_t *)tmc, 0, sizeof(tmc2240_t));
tmc->timer = timer;
tmc->time_ch = time_ch;
tmc->spi = spi_create(SPI_TYPE_NORMAL, *gpios, 0);
DBG_ASSERT(tmc->spi != NULL __DBG_LINE);
tmc->spi->interface.hardware_enable(tmc->spi, SPIx);
{
tmc->default_tm.sysclk = SystemCoreClock / 1000;
tmc->default_tm.psc = PWM_GET_PSC(tmc->timer);
tmc->default_tm.arr = PWM_GET_ARR(tmc->timer);
tmc->default_tm.freq = PWM_GET_FREQ(tmc->timer);
}
tmc->params.percent = TMC2240_PWM_DUTY_DEFAULT;
tmc->params.arr = 0;
tmc->params.freq = 0;
tmc->params.enable = FALSE;
tmc->params.direction = TMC2240_FORWARD;
tmc2240_config_write(index);
_tmc2240_motor_update(index);
}
tmc2240_t *tmc2240_get(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
return &_tmc2240[index];
}
void tmc2240_percent(tmc2240_index_e index, float32 percent)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
PWM_SET_DUTY(tmc->timer, tmc->time_ch, ABS(percent));
}
void tmc2240_config_read(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
tmc->read_config.gconf.data = tmc2240_reg_read(index, TMC2240_GCONF);
tmc->read_config.chopconf.data = tmc2240_reg_read(index, TMC2240_CHOPCONF);
tmc->read_config.drvconf.data = tmc2240_reg_read(index, TMC2240_DRV_CONF);
tmc->read_config.global_scaler.data = tmc2240_reg_read(index, TMC2240_GLOBAL_SCALER);
tmc->read_config.ihold_irun.data = tmc2240_reg_read(index, TMC2240_IHOLD_IRUN);
tmc->read_config.pwmconf.data = tmc2240_reg_read(index, TMC2240_PWMCONF);
tmc->read_config.gstat.data = tmc2240_reg_read(index, TMC2240_GSTAT);
tmc->data.tmc2240_adc_temp = tmc2240_reg_read(index, TMC2240_ADC_TEMP);
tmc->data.tmc2240_temperature = (float32)(tmc->data.tmc2240_adc_temp - 2038) / 7.7;
}
void tmc2240_test(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
_tmc2240_enable(index, tmc->params.enable);
if (tmc->params.enable == TRUE)
{
_tmc2240_direction(index, tmc->params.direction);
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
{
if (tmc->params.arr == 0)
{
tmc->params.arr = tmc->default_tm.arr;
}
PWM_SET_ARR(tmc->timer, tmc->params.arr);
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
}
tmc2240_percent(index, tmc->params.percent);
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
{
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
_tmc2240_motor_update(index);
}
}
}
void tmc2240_motor_set_angle(tmc2240_index_e index, int32_t angle)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (angle == 0)
{
return;
}
tmc->params.enable = FALSE;
_tmc2240_enable(index, tmc->params.enable);
tmc->motor.pulse_count = 0;
if (angle > 0)
{
tmc->params.direction = TMC2240_FORWARD;
}
else
{
tmc->params.direction = TMC2240_BACKWARD;
}
tmc->motor.pulse_count = ABS(angle) / tmc->motor.step_angle;
tmc->motor.step_angle_count = 0;
tmc->params.enable = TRUE;
_tmc2240_direction(index, tmc->params.direction);
if (PWM_GET_ARR(tmc->timer) != tmc->params.arr)
{
if (tmc->params.arr == 0)
{
tmc->params.arr = tmc->default_tm.arr;
}
PWM_SET_ARR(tmc->timer, tmc->params.arr);
tmc->params.freq = PWM_GET_FREQ(tmc->timer);
}
tmc2240_percent(index, tmc->params.percent);
if (tmc->config.chopconf.bits.mres != tmc->read_config.chopconf.bits.mres)
{
tmc2240_reg_write(index, TMC2240_CHOPCONF, tmc->config.chopconf.data);
_tmc2240_motor_update(index);
}
_tmc2240_enable(index, tmc->params.enable);
}
void tmc2240_motor_update(tmc2240_index_e index)
{
DBG_ASSERT(index < TMC2240_MAX __DBG_LINE);
tmc2240_t *tmc = &_tmc2240[index];
DBG_ASSERT(tmc != NULL __DBG_LINE);
if (tmc->motor.pulse_count > 0)
{
tmc->motor.pulse_count--; // 脉冲数
tmc->motor.step_angle_count++; // 步距个数
if (tmc->params.direction == TMC2240_FORWARD)
{
tmc->motor.add_pulse_count++; /* 绝对位置++ */
}
else
{
tmc->motor.add_pulse_count--; /* 绝对位置-- */
}
}
/* 当脉冲数等于0的时候 代表需要发送的脉冲个数已完成,停止输出 */
if (tmc->motor.pulse_count <= 0)
{
tmc->params.enable = FALSE;
_tmc2240_enable(index, tmc->params.enable);
}
}

372
tmc2240.h Normal file
View File

@ -0,0 +1,372 @@
/**
* @file tmc2240.h
* @author xushenghao
* @brief TMC2240驱动头文件
* @version 0.1
* @note
* 1. VM需要供电SPI无法正常通信
* 2. 421.812001/81=0.2251600
*/
#ifndef __TMC2240_H
#define __TMC2240_H
#include "main.h"
#include "spis.h"
#define MOTOR_42_STEP_ANGLE 1.8f // 42步进电机每步1.8度
#define TMC2240_PWM_DUTY_DEFAULT 50 // PWM默认占空比
/*
0x00 = 0x00002108 ;; writing GCONF @ address 0=0x00 with 0x00002108=8456=0.0
0x03 = 0x00000000 ;; writing SLAVECONF @ address 1=0x03 with 0x00000000=0=0.0
0x04 = 0x4001682C ;; writing IOIN @ address 2=0x04 with 0x4001682C=1073834028=0.0
0x0A = 0x00000021 ;; writing DRV_CONF @ address 3=0x0A with 0x00000021=33=0.0
0x0B = 0x00000000 ;; writing GLOBAL_SCALER @ address 4=0x0B with 0x00000000=0=0.0
0x10 = 0x00001208 ;; writing IHOLD_IRUN @ address 5=0x10 with 0x00001208=4616=0.0
0x11 = 0x00000000 ;; writing TPOWERDOWN @ address 6=0x11 with 0x00000000=0=0.0
0x13 = 0x00000000 ;; writing TPWMTHRS @ address 7=0x13 with 0x00000000=0=0.0
0x14 = 0x000003BE ;; writing TCOOLTHRS @ address 8=0x14 with 0x000003BE=958=0.0
0x15 = 0x00000000 ;; writing THIGH @ address 9=0x15 with 0x00000000=0=0.0
0x2D = 0x00000000 ;; writing DIRECT_MODE @ address 10=0x2D with 0x00000000=0=0.0
0x38 = 0x00000000 ;; writing ENCMODE @ address 11=0x38 with 0x00000000=0=0.0
0x39 = 0x00000000 ;; writing X_ENC @ address 12=0x39 with 0x00000000=0=0.0
0x3A = 0x00010000 ;; writing ENC_CONST @ address 13=0x3A with 0x00010000=65536=0.0
0x52 = 0x0B920F25 ;; writing OTW_OV_VTH @ address 14=0x52 with 0x0B920F25=194121509=0.0
0x60 = 0xAAAAB554 ;; writing MSLUT[0] @ address 15=0x60 with 0xAAAAB554=0=0.0
0x61 = 0x4A9554AA ;; writing MSLUT[1] @ address 16=0x61 with 0x4A9554AA=1251300522=0.0
0x62 = 0x24492929 ;; writing MSLUT[2] @ address 17=0x62 with 0x24492929=608774441=0.0
0x63 = 0x10104222 ;; writing MSLUT[3] @ address 18=0x63 with 0x10104222=269500962=0.0
0x64 = 0xFBFFFFFF ;; writing MSLUT[4] @ address 19=0x64 with 0xFBFFFFFF=0=0.0
0x65 = 0xB5BB777D ;; writing MSLUT[5] @ address 20=0x65 with 0xB5BB777D=0=0.0
0x66 = 0x49295556 ;; writing MSLUT[6] @ address 21=0x66 with 0x49295556=1227445590=0.0
0x67 = 0x00404222 ;; writing MSLUT[7] @ address 22=0x67 with 0x00404222=4211234=0.0
0x68 = 0xFFFF8056 ;; writing MSLUTSEL @ address 23=0x68 with 0xFFFF8056=0=0.0
0x69 = 0x00F70000 ;; writing MSLUTSTART @ address 24=0x69 with 0x00F70000=16187392=0.0
0x6C = 0x00410153 ;; writing CHOPCONF @ address 25=0x6C with 0x00410153=4260179=0.0
0x6D = 0x00040000 ;; writing COOLCONF @ address 26=0x6D with 0x00040000=262144=0.0
0x70 = 0xC44C001E ;; writing PWMCONF @ address 27=0x70 with 0xC44C001E=0=0.0
0x74 = 0x00000000 ;; writing SG4_THRS @ address 28=0x74 with 0x00000000=0=0.0
*/
#define TMC2240_GCONF 0x00
#define TMC2240_GSTAT 0x01
#define TMC2240_IFCNT 0x02
#define TMC2240_SLAVECONF 0x03
#define TMC2240_IOIN 0x04
#define TMC2240_DRV_CONF 0x0A
#define TMC2240_GLOBAL_SCALER 0x0B
#define TMC2240_IHOLD_IRUN 0x10
#define TMC2240_TPOWERDOWN 0x11
#define TMC2240_TSTEP 0x12
#define TMC2240_TPWMTHRS 0x13
#define TMC2240_TCOOLTHRS 0x14
#define TMC2240_THIGH 0x15
#define TMC2240_DIRECT_MODE 0x2D
#define TMC2240_ENCMODE 0x38
#define TMC2240_XENC 0x39
#define TMC2240_ENC_CONST 0x3A
#define TMC2240_ENC_STATUS 0x3B
#define TMC2240_ENC_LATCH 0x3C
#define TMC2240_ADC_VSUPPLY_AIN 0x50
#define TMC2240_ADC_TEMP 0x51
#define TMC2240_OTW_OV_VTH 0x52
#define TMC2240_MSLUT0 0x60
#define TMC2240_MSLUT1 0x61
#define TMC2240_MSLUT2 0x62
#define TMC2240_MSLUT3 0x63
#define TMC2240_MSLUT4 0x64
#define TMC2240_MSLUT5 0x65
#define TMC2240_MSLUT6 0x66
#define TMC2240_MSLUT7 0x67
#define TMC2240_MSLUTSEL 0x68
#define TMC2240_MSLUTSTART 0x69
#define TMC2240_MSCNT 0x6A
#define TMC2240_MSCURACT 0x6B
#define TMC2240_CHOPCONF 0x6C
#define TMC2240_COOLCONF 0x6D
#define TMC2240_DCCTRL 0x6E
#define TMC2240_DRVSTATUS 0x6F
#define TMC2240_PWMCONF 0x70
#define TMC2240_PWMSCALE 0x71
#define TMC2240_PWM_AUTO 0x72
#define TMC2240_SG4_THRS 0x74
#define TMC2240_SG4_RESULT 0x75
#define TMC2240_SG4_IND 0x76
#define TMC2240_HIGHT_BIT 0x80
typedef enum
{
TMC2240_1,
TMC2240_MAX,
} tmc2240_index_e;
typedef enum
{
TMC2240_FORWARD, // 正转
TMC2240_BACKWARD, // 反转
} tmc2240_direction_e;
typedef enum
{
TMC2240_MRES_256,
TMC2240_MRES_128,
TMC2240_MRES_64,
TMC2240_MRES_32,
TMC2240_MRES_16,
TMC2240_MRES_8,
TMC2240_MRES_4,
TMC2240_MRES_2,
TMC2240_MRES_1, // FULL STEP
} tmc2240_mres_e;
// 0x00 GCONF
typedef union
{
uint32_t data;
struct
{
uint32_t reserved1 : 1;
/**
*
* 0x02^20
* 0x12^18
*/
uint32_t fast_standstill : 1;
/**
* StealthChop2模式
* 0x0StealthChop2
* 0x1StealthChop2电压PWM模式使能()
lHOLD =
*/
uint32_t en_pwm_mode : 1;
/**
* StealthChop2的步进输入筛选
* 0x0StealthChop2
* 0x1StealthChop2电压PWM模式使能
()
lHOLD=
*/
uint32_t multistep_filt : 1;
/**
* /
* 0x0
* 0x1
*/
uint32_t shaft : 1;
uint32_t diag0_error : 1;
uint32_t diag0_otpw : 1;
uint32_t diag0_stall : 1;
uint32_t diag1_stall : 1;
uint32_t diag1_index : 1;
uint32_t diag1_onstate : 1;
uint32_t reserved2 : 1;
uint32_t diag0_pushpull : 1;
uint32_t diag1_pushpull : 1;
uint32_t small_hysteresis : 1;
/**
*
* 0x0
* 0x1ENCA停止定序器
(
)
*/
uint32_t stop_enable : 1;
/**
* motpr相电流控制
* 0x0
* 0x1线
(0x2D)线A
(8..0)线B电流(24..16)
lHOLD设置进行定标
StealthChop2电流调节
StealthChop2电流调节仅适用于
*/
uint32_t direct_mode : 1;
} bits;
} gconf_u;
// 0x01 GSTAT
typedef union
{
uint32_t data;
struct
{
uint32_t reset : 1;
uint32_t drv_err : 1;
uint32_t uv_cp : 1;
uint32_t register_reset : 1;
uint32_t vm_uvlo : 1;
} bits;
} gstat_u;
// 0x0A DRVCONF
typedef union
{
uint32_t data;
struct
{
uint32_t current_range : 2; // 0-1
uint32_t reserved1 : 2; // 2-3
uint32_t slope_control : 2; // 4-5
} bits;
} drvconf_u;
// 0x0B GLOBAL_SCALER
typedef union
{
uint32_t data;
struct
{
uint32_t global_scale : 8; // 0-7
} bits;
} global_scaler_u;
// 0x10 IHOLD_IRUN
typedef union
{
uint32_t data;
struct
{
uint32_t ihold : 5; // 0-4
uint32_t reserved1 : 3; // 5-7
uint32_t irun : 5; // 8-12
uint32_t reserved2 : 3; // 13-15
uint32_t iholddelay : 4; // 16-19
uint32_t reserved3 : 4; // 20-23
uint32_t irundelay : 4; // 24-27
} bits;
} ihold_irun_u;
// 0x6C CHOPCONF
typedef union
{
uint32_t data;
struct
{
uint32_t toff : 4; // 0-3
uint32_t hstrt : 3; // 4-6
uint32_t hend : 4; // 7-10
uint32_t fd3 : 1; // 11
uint32_t disfdcc : 1; // 12
uint32_t reserved1 : 1;
uint32_t chm : 1; // 14
uint32_t tbl : 2; // 15-16
uint32_t reserved2 : 1;
uint32_t vhighfs : 1; // 18
uint32_t vhighchm : 1; // 19
uint32_t tpfd : 4; // 20-23
uint32_t mres : 4; // 24-27
uint32_t intpol : 1; // 28
uint32_t dedge : 1; // 29
uint32_t diss2g : 1; // 30
uint32_t diss2vs : 1; // 31
} bits;
} chopconf_u;
// 0x70 PWMCONF
typedef union
{
uint32_t data;
struct
{
/**
* PWM 0-255CS_ACTUAL=31 =30 使 PWM_OFS
* PWM_OFS pwm_autoscale 0 pwm_autoscale 1
* StealthChop2 PWM_OFS = 0 使
* PWM_OFS > 0 PWM
* IHOLD_IRUN
*/
uint32_t pwm_ofs : 8;
/**
* PWM PWM_GRAD x 256 / TSTEP PWM_OFS 使 PWM_GRAD
* PWM_GRAD pwm_autoscale 0 pwm_autoscale 1
* StealthChop2 PWM_GRAD_AUTO
*/
uint32_t pwm_grad : 8;
uint32_t pwm_freq : 2;
uint32_t pwm_autoscale : 1;
uint32_t pwm_autograd : 1;
} bits;
} pwmconf_u;
typedef struct
{
gconf_u gconf; // 0x00 GCONF
gstat_u gstat; // 0x01 GSTAT
drvconf_u drvconf; // 0x0A DRVCONF
global_scaler_u global_scaler; // 0x0B GLOBAL_SCALER
ihold_irun_u ihold_irun; // 0x10 IHOLD_IRUN
chopconf_u chopconf; // 0x6C CHOPCONF
pwmconf_u pwmconf; // 0x70 PWMCONF
} tmc2240_config_t;
typedef struct
{
gpio_t *en; ///< EN_PIN
gpio_t *dir; ///< DIR_PIN
TIM_TypeDef *timer;
uint32_t time_ch;
spi_t *spi;
tmc2240_config_t config;
tmc2240_config_t read_config;
uint32_t step;
__IO uint32_t step_count;
// PRIVATE
struct
{
uint32_t sysclk; // 系统时钟
uint32_t psc; // 预分频系数
uint16_t arr; // 自动重装值 auto reload value
uint32_t freq; // 频率
} default_tm;
struct
{
BOOL enable; // 使能
tmc2240_direction_e direction; // 方向
float32 percent; // 占空比
uint16_t arr; // 自动重装值(改变速度)
uint32_t freq; // 频率
} params;
struct
{
float32 step_angle; // 步进角度
uint16_t circle_pulse; // 一圈脉冲数
__IO int32_t add_pulse_count; /* 脉冲个数累计 */
__IO uint32_t pulse_count; /* 脉冲个数记录 */
__IO uint32_t step_angle_count; /* 步距个数 */
} motor;
struct
{
uint16_t tmc2240_adc_temp; // 温度ADC值
float32 tmc2240_temperature; // 温度
} data;
} tmc2240_t;
void tmc2240_init(tmc2240_index_e index, SPI_TypeDef *SPIx, TIM_TypeDef *timer, uint32_t time_ch, spi_gpio_group_t *gpios);
tmc2240_t *tmc2240_get(tmc2240_index_e index);
void tmc2240_motor_set_angle(tmc2240_index_e index, int32_t angle);
void tmc2240_motor_update(tmc2240_index_e index);
void tmc2240_test(tmc2240_index_e index);
void tmc2240_config_read(tmc2240_index_e index);
#endif // __TMC2240_H