【无标题】STM32103FC8-DMA—直接存储区访问学习

1.添加基础库

stm 官网下载地址:https://doc.embedfire.com/products/link/zh/latest/mcu/stm32/stm32f103c8t6_core_new1.html

项目参数配置:

Preprocessor Symbols Define 设置参数:

USE_STDPERIPH_DRIVER,USE_STM3210C_EVAL

#需要添加的文件:

mcu 配置:startup_stm32f10x_hd.s

core 配置:Libraries\CMSIS\CM3\CoreSupport 所有文件

inc配置:Libraries\STM32F10x_StdPeriph_Driver\inc 文件夹所有文件

src配置:Libraries\STM32F10x_StdPeriph_Driver\src 文件夹所有文件

eval 配置: Utilities\STM32_EVAL\STM3210C_EVAL 文件夹所有文件

fonts 配置:Utilities\STM32_EVAL\Common\fonts.h 文件

项目配置:Project\STM32F10x_StdPeriph_Examples\SysTick\TimeBase 文件夹下 【stm32f10x_conf.h,stm32f10x_it.c,stm32f10x_it.h,system_stm32f10x.c】

源码:

c 复制代码
#include "stm32f10x.h"
#include "stm32_eval.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_it.h"
#include "stm32_eval.h"
#include "stm32f10x_rcc.h"

//当使用存储器到存储器模式时候,通道可以随便选,没有硬性的规定
#define DMA_CHANNEL 						DMA1_Channel6
#define DMA_CLOCK								RCC_AHBPeriph_DMA1		
//传输完成标志
#define DMA_FLAG_TC							DMA1_FLAG_TC6
//要发送的数据大小
#define BUFFER_SIZE							32

#define DEBUG_USARTx 						USART1
#define DEBUG_USART_CLK					RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd	RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE		115200


//usart gpio 引脚定义
#define DEBUG_USART_GPIO_CLK		(RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd

#define DEBUG_USART_TX_GPIO_PROT GPIOA
#define DEBUG_USART_TX_GPIO_PIN	 GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN	 GPIO_Pin_10

//串口对应的DMA请求通带
#define USART_TX_DMA_CHANNEL		 DMA1_Channel4
//外设寄存器地址
#define USART_DR_ADDRESS				 (USART1_BASE+0x04)
//一次发送的数据量
#define SENDBUF_SIZE							5000
//定义DMA传输目标存储器 存储器在内部的SRAM中
uint32_t aDST_BUffer[BUFFER_SIZE];

const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = 
{
	0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
	0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
	0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
	0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
	0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
	0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
	0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
	0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80
};


void DMA_Config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	//开启DMA时钟
	RCC_AHBPeriphClockCmd(DMA_CLOCK,ENABLE);
	//源数据地址
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) aSRC_Const_Buffer;
	//目标地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) aDST_BUffer;
	//方向:外设到存储器(这里的外设时内部FLASH)
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	//传输大小
	DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
	//外设(内部的Flash) 地址递增
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
	//内存地址递增
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	//外设数据单位
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
	//内存数据单位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
	//DMA 模式,一次或者循环模式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;
	//优先级:高
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	//使能内存到内存的传输
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
	//配置DMA通道
	DMA_Init(DMA_CHANNEL,&DMA_InitStructure);
	//使能DMA
	DMA_Cmd(DMA_CHANNEL,ENABLE);
}

uint8_t Buffercmp(const uint32_t* pBuffer,uint32_t* pBuffer1,uint16_t BufferLength) 
{
	//数据长度递减
	while(BufferLength --) 
	{
		//判断两个数据源是否对应相等
		if(*pBuffer != *pBuffer1)
		{
			//对应数据源不相等,满上退出函数,返回0
			return 0;
		}
		//递增两个数据源的地址指针
		pBuffer ++ ;
		pBuffer1 ++;
	}
	//完成判断并且对应数据相对
	return 1;
}




void USARTx_DMA_Config(void) 
{
	DMA_InitTypeDef DMA_InitStucture;
	//开启DMA时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	//设置DMA源地址:串口数据寄存器地址
	DMA_InitStucture.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
	//内存地址(要传输的变量的指针)
//	DMA_InitStucture.DMA_MemoryBaseAddr = (u32) Send;
	
}



void Delay(__IO uint32_t nCount)     //简单的延时函数
{
    for (; nCount != 0; nCount--);
}	

/**
* 微妙级延时(适配任意主频,依赖SystemCoreClock 全局变量)
* @parems us 延时的微妙数
*/
void delay_us(uint32_t us)
{
	SysTick ->LOAD = (SystemCoreClock / 1000000) * us -1; 									// 设置重载值,72MHz 下1us 计数72次
	SysTick ->VAL = 0x00;   																								//清空当前计数值
	SysTick ->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;	//使能SysTick  时
	while(!(SysTick ->CTRL & SysTick_CTRL_COUNTFLAG_Msk));									//等待计数完成
	SysTick ->CTRL = 0x00;																									//关闭SysTick
	
}

void LED_GPIO_Config(void) 
{
	/*定义一个GPIO_InitTypeDef 类型的结构体*/
	GPIO_InitTypeDef GPIO_InitSture;
	/*开启LED相关的GPIO外设时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	/*选择要控制的GPIO引脚*/
	GPIO_InitSture.GPIO_Pin = GPIO_Pin_1| GPIO_Pin_2 | GPIO_Pin_3;
	
	/*选择引脚模式为通用推挽输出*/
	GPIO_InitSture.GPIO_Mode = GPIO_Mode_Out_PP;
	
	GPIO_InitSture.GPIO_Speed = GPIO_Speed_50MHz;
	/*设置引脚的速率为50HZ*/
	GPIO_Init(GPIOA,&GPIO_InitSture);
  
	GPIO_SetBits(GPIOA,GPIO_Pin_1| GPIO_Pin_2 | GPIO_Pin_3);

}

int main(void)
{
//	  SystemInit(); 
		//定义存放比较结果变量
		uint8_t TransferStatus;
		//LED 端口初始化
		LED_GPIO_Config();
		
		//设置蓝灯亮
		GPIO_ResetBits(GPIOA,GPIO_Pin_3);
		
		//设置延时函数
		delay_us(5000000);
		//DMA 传输配置
		DMA_Config();
		//等待DMA传输完成
		while(DMA_GetFlagStatus(DMA_FLAG_TC) == RESET) {}
	
		//比较源数据与传输后的数据
		TransferStatus = Buffercmp(aSRC_Const_Buffer,aDST_BUffer,BUFFER_SIZE);
			
		//判断源数据与传输后数据比较结果
		if(TransferStatus == 0)
		{
			//源数据与传输后数据不相等的RGB彩色灯显示红色
			GPIO_ResetBits(GPIOA,GPIO_Pin_1);
		}
		else 
		{
			//源数据与传输后数据不相等的RGB彩色灯显示绿色
			GPIO_ResetBits(GPIOA,GPIO_Pin_2);
		}
			
		while(1){
		
		}
}

参考文档:

https://doc.embedfire.com/mcu/stm32/f103zhinanzhe/std/zh/latest/book/DMA.html

实现光敏电阻采集,OLED 屏幕显示,串口输出当前的光敏电阻值

OLED 显示,参考网站:

https://github.com/WDWD5875/OLED-Mpu6050-DMP-STM32F103C8T6/tree/main

OLED 引脚相关的内容:

名称 说明
VCC 供电 3.3V
GND 地线
SCL IIC时钟引脚
SDA IIC数据引脚

数据手册内容:

光敏电阻引脚:

名称 说明
VCC 供电 3.3V
GND 地线
DO 数字量数据
AO 模拟量数据
c 复制代码
#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>

#include "oled_ssd1306.h"
#include "mpu6050_dmp.h"
#include "mpu_port_i2c.h"

/*======================= 参数配置 =======================*/
#define ADC_BUF_SIZE        256     // ADC DMA 缓冲区大小(256点取平均,数据更稳)
#define SERIAL_BAUDRATE     115200  // 串口波特率
#define R_DIVIDER           10000.0f// 分压电阻阻值 10KΩ
#define ADC_VREF            3.3f    // ADC 参考电压

/*======================= 全局变量 =======================*/
uint16_t adc_dma_buf[ADC_BUF_SIZE];  // ADC DMA 硬件缓冲区
volatile uint8_t  adc_new_data = 0;  // 新数据就绪标志
volatile uint16_t adc_avg_val = 0;   // 滤波后的ADC平均值

/*======================= 简易延时 =======================*/

void delay_us(uint32_t us)
{
    uint32_t temp;
    SysTick->LOAD = SystemCoreClock / 8 / 1000000 * us - 1;
    SysTick->VAL = 0;
    SysTick->CTRL |= 0x01;
    do {
        temp = SysTick->CTRL;
    } while((temp & 0x01) && !(temp & (1<<16)));
    SysTick->CTRL &= ~0x01;
    SysTick->VAL = 0;
}

void delay_ms(uint32_t ms) { while(ms--) delay_us(1000); }

/*======================= 重定向 printf 到串口 =======================*/
// 重写 fputc,让 printf 直接输出到串口
int fputc(int ch, FILE *f)
{
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, (uint8_t)ch);
    return ch;
}


/*======================= USART 初始化 =======================*/
void USART_Init_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
    
    // PA9 TX 复用推挽输出
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // PA10 RX 浮空输入
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 串口参数:115200 8N1
    USART_InitStructure.USART_BaudRate            = SERIAL_BAUDRATE;
    USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits            = USART_StopBits_1;
    USART_InitStructure.USART_Parity              = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode                = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStructure);
    
    USART_Cmd(USART1, ENABLE);
}

/*======================= ADC + DMA 初始化 =======================*/
void ADC_DMA_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
		uint32_t timeout; // 超时计数,防止死循环
		// 开时钟(注意顺序:先开DMA时钟,再开ADC时钟)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // PA0 模拟输入
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	
    delay_ms(10);
    // DMA1 通道1 -> ADC1(循环模式)
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)adc_dma_buf;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize         = ADC_BUF_SIZE;
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_Medium;
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    // 先关闭所有DMA中断,清除所有标志
		DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT | DMA_IT_TE, DISABLE);
    DMA_ClearITPendingBit(DMA1_IT_TC1 | DMA1_IT_HT1 | DMA1_IT_TE1);
    DMA_Cmd(DMA1_Channel1, ENABLE);
		
    // ADC配置:12位 连续转换
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // ADC时钟 72M/6 = 12MHz
    ADC_DeInit(ADC1);
		delay_ms(5);
    
    ADC_InitStructure.ADC_Mode               = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode       = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv   = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign          = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel       = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
    
		 // ===== 关键修复2:ADC上电,等待稳定后再校准 =====
    ADC_Cmd(ADC1, ENABLE);
    delay_ms(5);  // 必须等ADC上电稳定(至少tSTAB = 1us,这里给5ms足够)
		
    // ADC校准
    ADC_ResetCalibration(ADC1);
		timeout = 100000;
    while(ADC_GetResetCalibrationStatus(ADC1))
		{
			timeout--;
      if(timeout == 0) break; // 超时直接退出,不再死等
		};
		
		// 开始校准
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1))
		{
        timeout--;
        if(timeout == 0) break; // 超时直接退出
    }
    
		// ===== 关键修复4:校准完成后,再开启DMA和软件触发 =====
    ADC_DMACmd(ADC1, ENABLE);
		// 清除所有ADC标志位
    ADC_ClearFlag(ADC1, ADC_FLAG_EOC | ADC_FLAG_JEOC | ADC_FLAG_AWD);
		// 开DMA传输完成中断
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
		
		// ===== 补上这三行 =====
    ADC_Cmd(ADC1, ENABLE);
    delay_ms(2);
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    // ======================
    
    // DMA中断配置
    NVIC_InitStructure.NVIC_IRQChannel                   = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 2;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/*======================= DMA 中断:均值滤波 =======================*/
void DMA1_Channel1_IRQHandler(void)
{
    uint32_t sum = 0;
    uint16_t i;
    
    if(DMA_GetITStatus(DMA1_IT_TE1)) DMA_ClearITPendingBit(DMA1_IT_TE1);
    if(DMA_GetITStatus(DMA1_IT_HT1)) DMA_ClearITPendingBit(DMA1_IT_HT1);
    
    if(DMA_GetITStatus(DMA1_IT_TC1)) {
        DMA_ClearITPendingBit(DMA1_IT_TC1);
        
        // 256个点取平均,消除工频噪声
        for(i = 0; i < ADC_BUF_SIZE; i++) {
            sum += adc_dma_buf[i];
        }
        adc_avg_val = (uint16_t)(sum / ADC_BUF_SIZE);
        adc_new_data = 1; // 标记有新数据
    }
}

/**
 * @brief  uint16_t整数转字符串
 * @param  num: 要转换的数字
 * @param  str: 输出的字符串缓存
 * @retval 字符串长度
 */
uint8_t Num2Str(uint16_t num, char *str)
{
    uint8_t i = 0, j = 0;
    char tmp[6]; // 最大支持65535,共5位数字
    if(num == 0) {
        str[0] = '0';
        str[1] = '\0';
        return 1;
    }
    // 逐位取数字(倒序)
    while(num > 0) {
        tmp[i++] = num % 10 + '0';
        num /= 10;
    }
    // 反转成正序
    for(j = 0; j < i; j++) {
        str[j] = tmp[i - 1 - j];
    }
    str[i] = '\0'; // 字符串结束符
    return i;
}


/**
 * @brief  float转字符串(保留2位小数,自动四舍五入)
 * @param  f: 要转换的浮点数(支持0~999范围,足够光敏/电压用)
 * @param  str: 输出字符串数组,建议长度≥8
 */
void float2str(float f, char *str)
{
    uint8_t i = 0;
    uint16_t integer_part;  // 整数部分
    uint16_t decimal_part;  // 小数部分
    
    // 1. 拆分整数和小数(+0.5是四舍五入)
    integer_part = (uint16_t)f;
    decimal_part = (uint16_t)((f - integer_part) * 100 + 0.5f); 
    
    // 处理小数进位(比如1.995+0.5=2.00的情况)
    if(decimal_part >= 100) {
        integer_part += 1;
        decimal_part -= 100;
    }
    
    // 2. 整数部分转字符串(倒序存,再反转)
    char tmp[8];
    uint8_t len = 0;
    if(integer_part == 0) {
        tmp[len++] = '0';
    } else {
        while(integer_part > 0) {
            tmp[len++] = integer_part % 10 + '0';
            integer_part /= 10;
        }
    }
    // 反转整数部分到str
    for(i = 0; i < len; i++) {
        str[i] = tmp[len - 1 - i];
    }
    str[len++] = '.'; // 加小数点
    
    // 3. 小数部分转字符串(固定2位,不足补0)
    str[len++] = decimal_part / 10 + '0'; // 十分位
    str[len++] = decimal_part % 10 + '0'; // 百分位
    str[len] = '\0'; // 必须加字符串结束符
}


/*======================= 主函数 =======================*/
int main(void)
{
    float voltage;      // PA0 电压值
    float r_light;      // 光敏电阻阻值
    uint8_t brightness; // 亮度百分比
		char str_buf[16]; // 显示用的字符串缓存
    
    SystemInit();
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    USART_Init_Config();  // 初始化串口
    ADC_DMA_Init();       // 初始化ADC+DMA
    oled_init();
		mpu6050_dmp_i2c_init();
		oled_clear();
		oled_show_string(1, 1, "OLED OK"); // 先验证 OLED 本身没问题
    // 开机提示
    printf("  STM32 Light Sensor Demo  \r\n");
    while(1)
    {
        if(adc_new_data) // 有新的ADC数据
        {
            adc_new_data = 0;
            
            // 1. 计算电压值
            voltage = (float)adc_avg_val * ADC_VREF / 4095.0f;
            
            // 2. 计算光敏电阻阻值(分压公式反推)
            // 分压电路:3.3V → R_light → PA0 → R_divider(10K) → GND
            // Vadc = 3.3 × R_divider / (R_light + R_divider)
            // 反推:R_light = R_divider × (3.3 / Vadc - 1)
            if(voltage < 0.01f) {
                r_light = 999999.0f; // 电压过低,阻值超大(完全黑暗)
            } else {
                r_light = R_DIVIDER * (ADC_VREF / voltage - 1.0f);
            }
            
            // 3. 计算亮度百分比(0=全黑,100=最亮)
            // 以3.3V为满量程估算,实际可根据光敏电阻型号校准
            brightness = (uint8_t)((float)adc_avg_val * 100 / 4095);
						float2str(r_light, str_buf);
						oled_show_string(1, 1, "Light Sendor:");
						oled_show_string(2, 1, str_buf);
            printf("light: %.1f\r\n",r_light);
						
            // 4. 串口输出(格式化显示)
//            printf("ADC value: %4d | voltage: %.3f V | resistance: %.1f KΩ | brightness: %3d %% \r\n",
//                   adc_avg_val, voltage, r_light / 1000.0f, brightness);
        }
        
        delay_us(50); // 1秒输出一次,可自行调整刷新频率
    }
}
相关推荐
深圳市恒锐丰科技杨生13 分钟前
SA8317E 2.7‑15V 单通道 H 桥电机驱动芯片|消费类低压直流有刷电机方案
嵌入式硬件·硬件工程
单片机仿真设计21 分钟前
【proteus仿真】基于 STM32 单片机六足机器人设计
stm32·单片机·嵌入式硬件·proteus·毕设
存在morning21 分钟前
【Flink SQL 学习笔记 三】维表关联:Lookup Join、Temporal Join、窗口 Join
sql·学习·flink
你想知道什么?27 分钟前
提示词工程-学习笔记
笔记·学习
minglie128 分钟前
vivado中视频ip相关接口
学习
louis.D.38 分钟前
gpio完整速查卡
单片机·嵌入式硬件
zcmodeltech40 分钟前
垃圾发电厂沙盘模型控制系统设计与实现:多设备协同联动方案
java·大数据·数据库·人工智能·stm32·嵌入式硬件·制造
゛凌乱的记忆づ1 小时前
50元从零到成品:一套AI辅助的嵌入式实战入门教程——中断篇
单片机·嵌入式硬件
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(53):Experience-Following——为什么错误经验会在记忆中不断传播
论文阅读·人工智能·学习·开源·github