- 2025-01-21
-
回复了主题帖:
【Follow me第二季第3期】任务提交
本次活动提供的开发板是EK-RA6M5,主芯片R7FA6M5BH3CFC,是一款功能非常强大的开发板,因此,仅需要购买相应的开发板就能完成所有任务。
所有任务如视频所示。
https://www.bilibili.com/video/BV1gDwxeQEeY/
任务一:00:10
任务二:01:58
任务三:03:06
任务四:04:27
本次任务是在快速开始实例程序中实现的,主要框架不变,只是在原有代码上增加一些功能,主要流程图如:
心得体会:非常感谢得捷和EEWorld提供的这次学习机会!经过本次学习,了解了瑞萨芯片R7FA6M5BH3CFC 的强大功能,学到了很多知识,比如菜单功能,ADC等等。以前接触到的单片机都是一些外设较少的简单MCU。第一次接触到这么多外设,这么多功能的单片机,很多功能没有完全发掘出他们的潜力,还需要继续研究。芯片功能很强大,可能是因为我是新手,对开发环境不太熟悉,这款芯片得开发环境较以前接触得芯片,更难搭建。
代码链接:https://download.eeworld.com.cn/detail/%E5%B7%A6%E6%89%8B%E9%98%BF%E9%A3%9E/635741
- 2025-01-20
-
加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门
- 2025-01-15
-
回复了主题帖:
【Follow me第二季第4期】任务提交:全部任务
yilonglucky 发表于 2025-1-15 13:30 短接rec到GND,进入recovery模式试试
可能是图形编程工具的问题。刚才解决了,然后试了一下图形编程工具,又出现了。等会儿再试试解决。
-
发表了主题帖:
【Follow me第二季第3期】任务提交
本帖最后由 左手阿飞 于 2025-1-15 15:10 编辑
感谢得捷以及EEWorld论坛提供的这次学习机会,让我学到不少知识。现在对本次【Follow me第二季第3期】活动的任务做一次总结,有成功也有失败,但还是收获很多。
任务1:搭建环境,下载调试示例程序,Blink,按键
https://bbs.eeworld.com.cn/thread-1301685-1-1.html
在环境搭建中,看到很多网友环境有问题。我第一次也有工具链的问题,我采用的方式简单粗暴,直接重装。
在重装中,选择安装工具链。然后得到解决。
完成任务后,可显示LED闪烁频率和呼吸灯的PWM占空比。
任务2:quad-spi flash和octo-spi flash配置及读写速度测试
https://bbs.eeworld.com.cn/thread-1301884-1-1.html
实例中已经有QSPI和OSPI的对比选项,只要按下相应的按键,并输入数据大小,就可以对比;
任务3:示例程序中新增命令打印信息
https://bbs.eeworld.com.cn/thread-1304313-1-1.html
找到开始菜单,增加相应的行
然后增加相应的回调函数
然后菜单中就可以看到了。
任务4:设计一个类似信号发生器功能的例程
https://bbs.eeworld.com.cn/thread-1304315-1-1.html
最后扩展任务,设计一个类似信号发生器例程。
信号发生器需要有相应波形的原始波形数据。
在这个任务卡了很多天了,也参考了其他大佬的帖子,但是还是没搞定,做了一些二级菜单,波形出不来。
展示一下现有成果吧。
增加了一个一级菜单,
-
回复了主题帖:
【Follow me第二季第4期】任务提交:全部任务
戈壁滩上的辉煌 发表于 2025-1-15 11:48
可以图形化编程?试试能不能通过选择板子的方式进行连接,应该是固件掉了
重新刷了固件,刚才又好了
-
回复了主题帖:
【Follow me第二季第4期】-任务4:选做任务一(非必做):通过RGB LED不同颜色、亮...
Jacktang 发表于 2025-1-15 07:33
下面看一下演示视频。
没有视频上传吧
上传失败了。重新发了。在楼下。
-
回复了主题帖:
【Follow me第二季第4期】-任务4:选做任务一(非必做):通过RGB LED不同颜色、亮...
电子烂人 发表于 2025-1-15 10:53
这个滑动平均滤波是选取了多少个数据,会不会对效果有影响?
滑动平均滤波取得是10个数据。灯的变化可能会缓慢一点。
-
回复了主题帖:
【Follow me第二季第4期】-任务4:选做任务一(非必做):通过RGB LED不同颜色、亮...
-
加入了学习《直播回放: DigiKey FollowMe 第二季 第4期 Arduino Nano RP2040 Connect 任务讲解》,观看 Arduino Nano RP2040 Connect 任务讲解
-
发表了主题帖:
【Follow me第二季第4期】任务提交:全部任务
本帖最后由 左手阿飞 于 2025-1-15 11:20 编辑
悲剧了,显示不出串口了。后面录不了视频了。
很高兴能够参加本期Follow me活动。活动要求的任务如下:
必做任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!;
https://bbs.eeworld.com.cn/thread-1303458-1-1.html
必做任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据;
https://bbs.eeworld.com.cn/thread-1303469-1-1.html
必做任务三:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
https://bbs.eeworld.com.cn/thread-1303574-1-1.html
选做任务一(非必做):通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小;
https://bbs.eeworld.com.cn/thread-1304613-1-1.html
选做任务二(非必做):通过IMU数据结合机器学习算法,识别运动状态,并通过串口打印。
下面分别对各任务完成情况进行说明
任务一:搭建环境并开启第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!。
https://bbs.eeworld.com.cn/thread-1303458-1-1.html
这次的开发板支持Arduino IDE,开发环境设置比较简单。
1、官网下载Arduino IDE,安装;
2、打开IDE后,在工具(tool)中下载相应的支持包;
3、连结板子,自动识别板子型号及对应串口。
任务第一步Blink三色LED / 串口打印Hello DigiKey & EEWorld!
在任务中,分别LEDR、LEDG、LEDB进行PWM写入就行。
串口输出分为两步:
1、设置波特率;
2、打印输出相应内容(Hello DigiKey & EEWorld!)。
#include "WiFiNINA.h"
#define Led1 LEDR
#define Led2 LEDG
#define Led3 LEDB
float angle1;
float angle2;
float angle3;
void setup() {
// put your setup code here, to run once:
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
pinMode(Led3, OUTPUT);
for(int i =0; i < 5 ; i++)
{
digitalWrite(Led1, LOW);
digitalWrite(Led2, HIGH);
delay(200);
digitalWrite(Led2, LOW);
digitalWrite(Led3, HIGH);
delay(200);
digitalWrite(Led3, LOW);
digitalWrite(Led1, HIGH);
delay(200);
}
angle1 = 0.0;
angle2 = 0.0 + PI /3.0;
angle3 = 0.0 + 2.0 * PI /3.0;
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Hello Digikey & EEWorld");
angle1 += 0.01;
angle2 += 0.01;
angle3 += 0.01;
if(angle1 >= PI)
angle1 -= PI;
if(angle2 >= PI)
angle2 -= PI;
if(angle3 >= PI)
angle3 -= PI;
int a = sin (angle1) * 255;
int b = sin (angle2) * 255;
int c = sin (angle3) * 255;
analogWrite(Led1 ,a);
analogWrite(Led2 ,b);
analogWrite(Led3 ,c);
delay(50);
}
必做任务二:学习IMU基础知识,调试IMU传感器,通过串口打印六轴原始数据;
https://bbs.eeworld.com.cn/thread-1303469-1-1.html
任务二也比较简单。安装IMU对应的库LSM6DSOX.h,然后进行调用就行。
具体步骤:
1、陀螺仪初始化(设置采样频率);串口初始化(设置波特率),
2、采集陀螺仪数据,
3、串口打印响应数据。
#include <Arduino_LSM6DSOX.h>
float acc_x,acc_y,acc_z;
float gyro_x,gyro_y,gyro_z;
float temp;
int update_flag;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if(!IMU.begin())
{
Serial.println("Falled to initialize IMU");
while(1);
}
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
}
void loop() {
// put your main code here, to run repeatedly:
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
if (IMU.accelerationAvailable())
{
IMU.readAcceleration(acc_x,acc_y,acc_z);
update_flag = 1;
}
if (IMU.gyroscopeAvailable())
{
IMU.readGyroscope(gyro_x,gyro_y,gyro_z);
update_flag = 1;
}
if (IMU.temperatureAvailable())
{
IMU.readTemperatureFloat(temp);
update_flag = 1;
}
if (update_flag)
{
update_flag=0;
Serial.print(acc_x);
Serial.print(',');
Serial.print(acc_y);
Serial.print(',');
Serial.print(acc_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.print(gyro_y);
Serial.print(',');
Serial.print(gyro_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.println(temp);
delay(500);
}
}
任务3:学习PDM麦克风技术知识,调试PDM麦克风,通过串口打印收音数据和音频波形。
https://bbs.eeworld.com.cn/thread-1303574-1-1.html
该任务同样是需要相应的库“PDM.h”,本次用到的库,板载库已经自带,不需要单独下载。
具体步骤:
1、麦克风初始化(设置采样频率);串口初始化(设置波特率),
2、采集麦克风数据,
3、串口打印响应数据。
#include "PDM.h"
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
Serial.println(sampleBuffer[i]);
}
samplesRead=0;
}
delay(1);
}
void onPDMdata(){
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer,bytesAvailable);
samplesRead = bytesAvailable / 2;
}
选做任务一(非必做):通过RGB LED不同颜色、亮度显示PDM麦克风收到的声音大小;
https://bbs.eeworld.com.cn/thread-1304613-1-1.html
选做任务需要结合必做任务3和1,对采集到的数据进行处理。
观察任务3的数据,发现数据有两个问题:
1、数据波动较大;
2、会出现负值。
针对上面两个问题,进行数据处理,具体处理方式:
问题1、采用滑动平均滤波;
问题2、取绝对值。
解决上面两个问题之后,再用处理后的值控制LEDR和LEDG就行了。
#include "PDM.h"
#include "WiFiNINA.h"
#define Led1 LEDR
#define Led2 LEDG
#define Led3 LEDB
#define MAX_SIZE 10
int head = 0;
int tail = 0;
int count = 0;
int queue[MAX_SIZE];
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
int LEDR_Value;
int LEDG_Value;
double MIC_Value;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
//Serial.println(sampleBuffer[i]);
MIC_Value=get_sliding_average(sampleBuffer[i]);
Serial.println(MIC_Value);
LEDR_Value=map(MIC_Value, 1, 3000, 1, 255);
LEDG_Value=map(MIC_Value, 1, 3000, 255, 1);
// analogWrite(Led1 ,LEDR_Value);
// analogWrite(Led2 ,LEDG_Value);
analogWrite(Led2 ,LEDR_Value);
analogWrite(Led1 ,LEDG_Value);
}
samplesRead=0;
}
delay(1);
}
void onPDMdata(){
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer,bytesAvailable);
samplesRead = bytesAvailable / 2;
}
void enqueue(int value) {
if ((tail + 1) % MAX_SIZE == head) {
// 队列已满,需要先移除一个元素
head = (head + 1) % MAX_SIZE;
}
queue[tail] = value;
tail = (tail + 1) % MAX_SIZE;
count++;
}
int dequeue() {
int value = queue[head];
head = (head + 1) % MAX_SIZE;
count--;
return value;
}
double get_sliding_average(int new_value) {
static int init = 1;
if (init) {
// 初始化添加MAX_SIZE-1个0,保证头尾指针不会相遇
for (int i = 0; i < MAX_SIZE - 1; i++) {
enqueue(0);
}
init = 0;
}
// 添加新的样本值
enqueue(sqrt(new_value * new_value));
// 计算滑动平均值
double sum = 0;
for (int i = 0; i < count; i++) {
sum += queue[(head + i) % MAX_SIZE];
}
return sum / count;
}
自选任务:
本次还买了一个超声波测距。准备做一个倒车雷达。
本次使用的是米思齐(Mixly)软件。该软件是一个图形化编程软件,适合儿童编程,从小培养兴趣爱好。
1、在官网下载软件,可以一键安装。http://mixly.org/
2、下载相应的库
然后就可以进行编程了。
还可以看到相应的C语言。
- 2025-01-14
-
发表了主题帖:
【Follow me第二季第4期】-任务4:选做任务一(非必做):通过RGB LED不同颜色、亮...
由于任务3是PDM麦克风相关任务,所以本次选择的可选任务是通过LED显示麦克风收到声音大小。
本次任务是在任务3 的基础上,结合任务1,对代码进行修改。
主要思路是对麦克风的取值进行存储,然后控制LED灯亮度。本次只用到红灯和绿灯。
观测到任务3中,麦克风采集的数据有两个问题;
1、麦克风采集到的声音波动非常大,不利于LED的控制,如下图(图片来自任务3的内容);
2、采集到的数值会出现负值。
所以需要对采集到的数值进行处理。
本次处理的方式是,先求绝对值,将负值变为正值,再进行滑动平均滤波。
全部带码如下:
#include "PDM.h"
#include "WiFiNINA.h"
#define Led1 LEDR
#define Led2 LEDG
#define Led3 LEDB
#define MAX_SIZE 10
int head = 0;
int tail = 0;
int count = 0;
int queue[MAX_SIZE];
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
int LEDR_Value;
int LEDG_Value;
double MIC_Value;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
//Serial.println(sampleBuffer[i]);
MIC_Value=get_sliding_average(sampleBuffer[i]);
Serial.println(MIC_Value);
LEDR_Value=map(MIC_Value, 1, 3000, 1, 255);
LEDG_Value=map(MIC_Value, 1, 3000, 255, 1);
// analogWrite(Led1 ,LEDR_Value);
// analogWrite(Led2 ,LEDG_Value);
analogWrite(Led2 ,LEDR_Value);
analogWrite(Led1 ,LEDG_Value);
}
samplesRead=0;
}
delay(1);
}
void onPDMdata(){
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer,bytesAvailable);
samplesRead = bytesAvailable / 2;
}
void enqueue(int value) {
if ((tail + 1) % MAX_SIZE == head) {
// 队列已满,需要先移除一个元素
head = (head + 1) % MAX_SIZE;
}
queue[tail] = value;
tail = (tail + 1) % MAX_SIZE;
count++;
}
int dequeue() {
int value = queue[head];
head = (head + 1) % MAX_SIZE;
count--;
return value;
}
double get_sliding_average(int new_value) {
static int init = 1;
if (init) {
// 初始化添加MAX_SIZE-1个0,保证头尾指针不会相遇
for (int i = 0; i < MAX_SIZE - 1; i++) {
enqueue(0);
}
init = 0;
}
// 添加新的样本值
enqueue(sqrt(new_value * new_value));
// 计算滑动平均值
double sum = 0;
for (int i = 0; i < count; i++) {
sum += queue[(head + i) % MAX_SIZE];
}
return sum / count;
}
滑动平均滤波函数中,直接对采集到的数值进行取绝对值;
在主程序中,通过映射,将数值转换为1-255,控制LEDR和LEDG;当声音小的时候,绿灯亮,声音大的时候,红灯亮。
下面看一下演示视频。
-
发表了主题帖:
【Follow me第二季第3期】任务4:设计一个类似信号发生器功能的例程
本帖最后由 左手阿飞 于 2025-1-14 12:21 编辑
最后扩展任务,设计一个类似信号发生器例程。
信号发生器需要有相应波形的原始波形数据。
在这个任务卡了很多天了,也参考了其他大佬的帖子,但是还是没搞定,做了一些二级菜单,波形出不来。
展示一下现有成果吧。
增加了一个一级菜单,
static st_menu_fn_tbl_t s_menu_items[] =
{
{"Wave Generator" , wave_generator},
{"Hello Information" , Hello_display_menu},
{"Kit Information" , kis_display_menu},
{"Web Server" , eth_emb_display_menu},
{"Network Name Lookup" , eth_www_display_menu},
{"Quad-SPI and Octo-SPI Speed Comparison" , ext_display_menu},
{"Cryptography and USB High speed (MSC)" , enc_display_menu},
{"Next Steps", ns_display_menu },
{"", NULL }
};
在菜单中加入选项。但是在增加波形,编译就通不过了。
#define WAVE_TRIANGLE 1
#define WAVE_SQUARE 2
#define WAVE_SINE 3
uint16_t amplitude_scale;
uint16_t period_scale;
uint16_t wavetype;
// Function to get user input for customization
bool customize_wave(uint16_t* amplitude_scale, uint16_t* period_scale) {
char choice;
sprintf(s_print_buffer, "Use default wave settings? (y/n): ");
print_to_console((void*)s_print_buffer);
choice = input_from_console();
if (choice == 'n' || choice == 'N') {
// Prompt for amplitude scaling factor
sprintf(s_print_buffer, "Enter amplitude scaling factor (1-10): ");
print_to_console((void*)s_print_buffer);
// Assume input_from_console returns ASCII digits; convert to integer
char amp_input = input_from_console();
*amplitude_scale = (uint16_t)(amp_input - '0');
if (*amplitude_scale < 1 || *amplitude_scale > 10) {
*amplitude_scale = 1; // Default value if out of range
}
// Prompt for period scaling factor
sprintf(s_print_buffer, "Enter period scaling factor (1-10): ");
print_to_console((void*)s_print_buffer);
char per_input = input_from_console();
*period_scale = (uint16_t)(per_input - '0');
if (*period_scale < 1 || *period_scale > 10) {
*period_scale = 1; // Default value if out of range
}
return true; // Customized settings
}
// Use default settings
*amplitude_scale = 1;
*period_scale = 1;
return false; // Default settings
}
test_fn wave_generator(void) // Added
{
int8_t c = -1;
uint16_t buffer[3]; // Increased buffer size to store wave type, amplitude, and period
amplitude_scale = 1;
period_scale = 1;
// Clear the screen and move cursor to home position
sprintf(s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
print_to_console((void*)s_print_buffer);
// Display the wave control menu
sprintf(s_print_buffer,
"Wave Control:\r\n"
"1: Triangle Wave\r\n"
"2: Square Wave\r\n"
"3: Sine Wave\r\n"
"r: Read from flash\r\n"
"w: Write to flash\r\n"
"space: Exit\r\n");
print_to_console((void*)s_print_buffer);
while (CONNECTION_ABORT_CRTL != c)
{
c = input_from_console();
if ((MENU_EXIT_CRTL == c) || (CONNECTION_ABORT_CRTL == c))
{
break;
}
if (0 != c)
{
// Display the selected option
sprintf(s_print_buffer, "Selected option: %c\r\n", c);
print_to_console((void*)s_print_buffer);
if ('1' == c) {
wavetype = WAVE_TRIANGLE; // Select Triangle Wave
}
else if ('2' == c) {
wavetype = WAVE_SQUARE; // Select Square Wave
}
else if ('3' == c) {
wavetype = WAVE_SINE; // Select Sine Wave
}
else if ('r' == c) { // Read saved parameters from flash
readFromFlash(buffer);
sprintf(s_print_buffer, "Read from buffer: Wave Type=%d, Amplitude Scale=%d, Period Scale=%d\r\n",
buffer[0], buffer[1], buffer[2]);
print_to_console((void*)s_print_buffer);
wavetype = buffer[0];
amplitude_scale = buffer[1];
period_scale = buffer[2];
continue; // Continue to next iteration
}
else if ('w' == c) { // Write current parameters to flash
buffer[0] = wavetype;
buffer[1] = amplitude_scale;
buffer[2] = period_scale;
SaveWaveToFlash(buffer);
sprintf(s_print_buffer, "Wave parameters saved to flash.\r\n");
print_to_console((void*)s_print_buffer);
continue; // Continue to next iteration
}
else {
sprintf(s_print_buffer, "Invalid option selected.\r\n");
print_to_console((void*)s_print_buffer);
continue; // Continue to next iteration
}
// After selecting wave type, prompt for customization
if (wavetype == WAVE_TRIANGLE || wavetype == WAVE_SQUARE || wavetype == WAVE_SINE) {
bool is_custom = customize_wave(&litude_scale, &period_scale);
if (is_custom) {
sprintf(s_print_buffer, "Custom settings applied: Amplitude Scale=%d, Period Scale=%d\r\n",
amplitude_scale, period_scale);
}
else {
sprintf(s_print_buffer, "Default settings applied: Amplitude Scale=1, Period Scale=1\r\n");
}
print_to_console((void*)s_print_buffer);
}
}
}
// Clear the display menu event bit
xEventGroupClearBits(g_update_console_event, STATUS_DISPLAY_MENU_KIS);
return (0);
}
- 2025-01-11
-
发表了主题帖:
【Follow me第二季第3期】任务3:示例程序中新增命令打印信息
本期任务3:在实例程序中,增加命令打印信息
具体步骤如下:
1、找到menu_main.c文件,找到目录对应的列表,增加新的命令“Hello Information”,以及相应的函数“Hello_display_menu”;
2、增加相应的函数,函数的功能借用kis_display_menu;
(1)先在 menu_kis.h 中找到函数声明位置,声明函数 Hello_display_menu;
(2)menu_kis.c 中完成函数体 Hello_display_menu;函数体实现功能与 kis_display_menu函数一致,就简单的复制。
编译,下载之后,通过终端连接,可以看到,菜单列表里,增加一行:“Hello_display_menu”
输入数字1,显示板载信息,功能与 Kit Information一致。
-
发表了主题帖:
【Follow me第二季第3期】任务2:quad-spi flash和octo-spi flash配置及读写速度测试
本帖最后由 左手阿飞 于 2025-1-11 12:53 编辑
任务二:quad-spi flash和octo-spi flash配置及读写速度测试:
使用快速开始程序,内部已经有相应的功能函数,跟随视频一起完成。
主菜单内,数字5则是对比QSPI和OSPI读写速度(原文件为数字4),出现下面界面:
提示输入测试的大小,2KB到64KB,输入64,按TAB:
对比出QSPI和OSPI的读写速度。
后面分别对比32KB、16KB、8KB、4KB、2KB读写:
(32KB)
(16KB)
(8KB)
(4KB)
(2KB)
根据以上对比,读写时间基本和文件大小成正比,读写速度基本一样。
QSPI的速度和OSPI的速度对比:
写速度:QSPI的时间大约是OSPI的2倍,
读速度:QSPI的时间大约是OSPI的6倍。
- 2025-01-03
-
发表了主题帖:
【Follow me第二季第4期】-任务3:学习PDM麦克风技术知识,调试PDM麦克风,通过串...
本次任务为学习PDM麦克风,并打印麦克风采集到的数据。
1、麦克风不需要安装单独的库,在板载资源里有“PDM.h”;
2、初始化串口,启动PDM,选择通道及设置采样频率;如果启动失败,则打印启动PDM失败;
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
3、循环执行声音采样,并打印采样值;
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
Serial.println(sampleBuffer[i]);
}
samplesRead=0;
}
delay(1);
}
4、用串口查看数据;可选择数据才看,也可选择波形查看;波形查看更直观。
总体代码如下:
#include "PDM.h"
static const char channels = 1;
static const int frequncy = 24000;
short sampleBuffer[512];
volatile int samplesRead;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
PDM.onReceive(onPDMdata);
if(!PDM.begin(channels,frequncy))
{
Serial.println("Failed to start PDM!!!");
while(1);
}
}
void loop() {
// put your main code here, to run repeatedly:
if(samplesRead)
{
for(int i = 0; i < samplesRead; i++)
{
Serial.println(sampleBuffer[i]);
}
samplesRead=0;
}
delay(1);
}
void onPDMdata(){
int bytesAvailable = PDM.available();
PDM.read(sampleBuffer,bytesAvailable);
samplesRead = bytesAvailable / 2;
}
- 2025-01-02
-
发表了主题帖:
【Follow me第二季第4期】-任务2:学习IMU基础知识,调试IMU传感器,通过串口打印...
任务要求:打印加速度、角速度和温度
根据视频介绍,引入库LSM6DSOX.h
#include <Arduino_LSM6DSOX.h>
初始化之前,声明变量,存放相应数据:
float acc_x,acc_y,acc_z;
float gyro_x,gyro_y,gyro_z;
float temp;
int update_flag;
初始化中,对串口和陀螺仪进行初始化,并打印陀螺仪的采样频率:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if(!IMU.begin())
{
Serial.println("Falled to initialize IMU");
while(1);
}
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
}
循环函数中,为了更好的观察采样数据,循环打印采样频率,并打印三轴加速度、三轴角速度和温度
void loop() {
// put your main code here, to run repeatedly:
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
if (IMU.accelerationAvailable())
{
IMU.readAcceleration(acc_x,acc_y,acc_z);
update_flag = 1;
}
if (IMU.gyroscopeAvailable())
{
IMU.readGyroscope(gyro_x,gyro_y,gyro_z);
update_flag = 1;
}
if (IMU.temperatureAvailable())
{
IMU.readTemperatureFloat(temp);
update_flag = 1;
}
if (update_flag)
{
update_flag=0;
Serial.print(acc_x);
Serial.print(',');
Serial.print(acc_y);
Serial.print(',');
Serial.print(acc_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.print(gyro_y);
Serial.print(',');
Serial.print(gyro_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.println(temp);
delay(500);
}
}
全部代码如下:
#include <Arduino_LSM6DSOX.h>
float acc_x,acc_y,acc_z;
float gyro_x,gyro_y,gyro_z;
float temp;
int update_flag;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
if(!IMU.begin())
{
Serial.println("Falled to initialize IMU");
while(1);
}
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
}
void loop() {
// put your main code here, to run repeatedly:
Serial.print("Acc sample rate = ");
Serial.print(IMU.accelerationSampleRate());
Serial.println("Hz");
Serial.print("Gyro sample rate = ");
Serial.print(IMU.gyroscopeSampleRate());
Serial.println("Hz");
if (IMU.accelerationAvailable())
{
IMU.readAcceleration(acc_x,acc_y,acc_z);
update_flag = 1;
}
if (IMU.gyroscopeAvailable())
{
IMU.readGyroscope(gyro_x,gyro_y,gyro_z);
update_flag = 1;
}
if (IMU.temperatureAvailable())
{
IMU.readTemperatureFloat(temp);
update_flag = 1;
}
if (update_flag)
{
update_flag=0;
Serial.print(acc_x);
Serial.print(',');
Serial.print(acc_y);
Serial.print(',');
Serial.print(acc_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.print(gyro_y);
Serial.print(',');
Serial.print(gyro_z);
Serial.print(',');
Serial.print(gyro_x);
Serial.print(',');
Serial.println(temp);
delay(500);
}
}
运行 结果如下:
-
发表了主题帖:
【Follow me第二季第4期】-任务1:搭建环境并开启第一步Blink三色LED / 串口打印He...
一、搭建开发环境:
推荐使用的开发环境位AduinoIDE,正好原来使用过Arduino,已经安装好了,不需要再次安装。只需要添加相应开发板(RP2040)就可以使用了。
二、跟着视频完成LED闪烁和打印“Hello Digikey & EEWorld”;
视频中,延时时间为5ms,LED呼吸效果不好,闪烁太快。
我改为50 ms,呼吸想过更自然。
#include "WiFiNINA.h"
#define Led1 LEDR
#define Led2 LEDG
#define Led3 LEDB
float angle1;
float angle2;
float angle3;
void setup() {
// put your setup code here, to run once:
pinMode(Led1, OUTPUT);
pinMode(Led2, OUTPUT);
pinMode(Led3, OUTPUT);
for(int i =0; i < 5 ; i++)
{
digitalWrite(Led1, LOW);
digitalWrite(Led2, HIGH);
delay(200);
digitalWrite(Led2, LOW);
digitalWrite(Led3, HIGH);
delay(200);
digitalWrite(Led3, LOW);
digitalWrite(Led1, HIGH);
delay(200);
}
angle1 = 0.0;
angle2 = 0.0 + PI /3.0;
angle3 = 0.0 + 2.0 * PI /3.0;
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Hello Digikey & EEWorld");
angle1 += 0.01;
angle2 += 0.01;
angle3 += 0.01;
if(angle1 >= PI)
angle1 -= PI;
if(angle2 >= PI)
angle2 -= PI;
if(angle3 >= PI)
angle3 -= PI;
int a = sin (angle1) * 255;
int b = sin (angle2) * 255;
int c = sin (angle3) * 255;
analogWrite(Led1 ,a);
analogWrite(Led2 ,b);
analogWrite(Led3 ,c);
delay(50);
}
串口打印结果如下图。:
- 2024-12-12
-
发表了主题帖:
【Follow me第二季第3期】任务1:搭建环境,下载调试示例程序,Blink,按键
1,环境搭建:
本次安装的的是5.6.0版本。安装完成之后,无法开启连接器。重新安装,需要勾选连接器安装。如下图3所示,红色方框标出的勾选。
2、打开快速开始程序_quickstart。
3、跟视频学习Blink,按键程序。
1)、找到LED闪烁频率和 呼吸灯占空比的函数,在原来基础上 增加 一个状态:
2)运行显示主菜单,通过键盘进入Kit Information。
3)通过两个蓝色按键,控制LED1和LED2的闪烁频率和占空比。
但是显示有个问题,已经用红框标出来:温度显示两行,造成闪烁频率和占空比错位。
- 2024-10-31
-
发表了主题帖:
【2024 DigiKey创意大赛】会议声源追踪器
会议声源追踪器
作者:左手阿飞
作品简介
随着网络直播技术的发展,许多线下活动转移到线上,比如线上会议、网络课堂等。为进一步提高线上会议或网络课堂的收音质量,本设计提出一种会议声源追踪系统,主要功能如下:
1、声源定位,识别声音方向;
2、声源追踪,用步进电机控制麦克风方向,追踪声源,减少干扰噪声;(未完成)
3、检测会议室环境,上传云端,可以提醒工作人员提前开启空调等设备。
图1 作品照片
用到的物料及想用的作用如下:
1、sipeed麦克风阵列(MIC_ARRAY):用于声音的收集;
2、K210开发板:用于声音数据分析,识别声音方向,并发送相应数据给STM32F411;
3、STM32F411开发板:接收K210数据,并控制步进电机,改变麦克风阵列的方向,使麦克风正面对应声源;
4、SGP30&DHT11:SGP30为空气质量传感器,可检测空气中挥发性有机物(TVOC)和CO2的含量;DHT11为温湿度传感器,可检测温度和湿度;
5、ESP32S3开发板:将检测到的空气质量(TVOC、CO2、温度和湿度)数据上传到云端(阿里云),通过手机APP查看,在会议开始前,提前打开空调等设备。
二、系统框图
硬件设计包含硬件设计框图如图2所示:
图2 系统框图
声源方向检测部分,由麦克风阵列和K210卡发版完成。麦克风方向由STM32提供控制信号,控制两个步进电机调整。两个步进电机分别调整X轴方向和Y轴方向。空气质量检测部分,由传感器SGP30和DHT11检测,并通过ESP32连接WIFI上传阿里云,实现远程检测和控制。
三、各部分功能说明
第一部为声源方向检测部分,由麦克风阵列和K210卡发版完成。
图3 声源方向检测
麦克风阵列为sipeed厂家出厂,由6+1个麦克风,圆周均匀分布6个,中央1个。传输方式为I2S传输方式,可检测不同方向的声音强度。圆周上有12个串行LED,可显示声源方向。LED控制方式为串行数字控制,串行控制协议类似于SPI。
K210开发板资源丰富,自带LCD屏幕(480*320)和麦克风阵列接口,可直接与麦克风阵列连接。开发语言为microPython。microPython开发方便,有丰富的三方库可供使用,开发方便。
K210接收麦克风阵列检测到的声音数据,通过对6个麦克风的数据差值,计算出声源的方向及距离,并控制LED显示出相应方向,并将数据通过串口发送给STM32F411。
第二部分为方向控制部分。由STM32F411和2个步进电机组成。
图4 麦克风方向控制
STM32通过串口,接收声音方向数据,控制2个步进电机。2个步进电机分别控制x轴方向和Y轴方向的运动,使麦克风阵列正对声源方向,达到声音降噪的目的。
第三部分为会议室环境检测部分。由SPG30、DHT11和ESP32S3组成。
图5 会议室空气质量检测
SPG30可检测空气中TVOC、CO2的浓度。通过I2C通信协议传输,传输数据格式为6个字节一组数据,前三个字节传送TVOC浓度,后三字节传送CO2浓度。每个分组数据,有两个字节为数据字节(16位),第三字节位CRC校验位。
DHT11为温湿度检测传感器,通过单总线协议传输。每帧数据5个字节,前2个字节为湿度数据,紧接着2个字节为温度数据,最后一个字节为校验位。
ESP32S3接收SPG30和DHT11检测到的空气质量数据,上传阿里云平台。可在阿里云平台和手机APP上查看。APP上设置有开关,可远程控制一个LED。在实际应用中,LED可替换为空调、新风风扇、空气净化器等设备。如有必要,可增加开关,控制更多设备。
四、作品源码
https://download.eeworld.com.cn/detail/%E5%B7%A6%E6%89%8B%E9%98%BF%E9%A3%9E/634860
五、作品功能演示视频
六、项目总结
这是第一次参加得捷主办的创新设计大赛。经过这次大赛的练习,对嵌入式开发有了更深的理解。感谢得捷提供的这次难得的机会。
本次设计完成了一个会议声源追踪器。该设备可完成会议室声源方向追踪、空气环境检测以及空气质量改善等功能。由于时间较为紧迫,所选方案为开发时间最短、最容易实现的方案,存在一些问题。最大的问题就是成本太高。一共用到3个控制器:K210、STM32、ESP32。控制器功能有重复,后续可从降成本方向考虑,用ESP32+STM32方案或者单独使用其中一个控制器方案。其次,方案多采用库函数,对底层研究不够深入,设备运行效率较低。后续可试试从底层开发,提升自己手册阅读能力与开发能力。
总之,经过这次训练,个人的嵌入式开发水平有了很大提升,开阔了眼界,为后续工作提供更多思路。再次感谢得捷提供的机会,祝愿大赛越办越好!!!
开箱贴:https://bbs.eeworld.com.cn/thread-1294810-1-1.html
温湿度检测:https://bbs.eeworld.com.cn/thread-1296460-1-1.html
TVOC和CO2检测:https://bbs.eeworld.com.cn/thread-1294810-1-1.html
-
上传了资料:
声源定位