bigbat

  • 2024-06-14
  • 发表了主题帖: 【FireBeetle 2 ESP32 C6】电池供电和功耗检测测试

    测试介绍 ESP32C6的功率管理较为单一,功耗管理, 通过选择时钟频率、占空比、Wi-Fi工作模式和单独控制内部器件的电源,实现精准电源控制。ESP32C6设计四种功耗模式:Active、Modem-sleep、Light-sleep、Deep-sleep, Deep-sleep 模式下功耗低至7µA,并且该模式下可以保持低功耗存储器 (LP memory)的内容仍保持工作和RTC 定时器工作。 本次测试使用FireBeetle 2开发板和可调电源,使用esp_deep_sleep_start()函数可以进入deep_sleep模式。使用EXT0/1 wakeup中断唤醒。使用OLED显示屏测试内容。 测试设置 1、本来使用电池供电,但是电池供电不能改变电压,所以使用可调的电源来代替。本次测试电压为3.0V供电。 2、程序启动后测试MQTT模式通讯和在OLED屏显示内容。 将MQTT程序进行修改。执行如下命令 idf.py set-target esp32c6 idf.py menuconfig    3、使用延时函数来进入Deep-sleep函数。 测试程序 首先将MQTT的wifi密码设置完成,确认能够正常工作。   将该程序加入OLED SSD1306显示内容。 flash 重复数据问题 地址映射 Could not find `protoc` installation and this build crate cannot proceed without this knowledge. If `protoc` is installed and this crate had trouble finding it, you can set the `PROTOC` environment variable with the specific path to your installed `protoc` binary.You can download it from https://github.com/protocolbuffers/protobuf/releases or from your package manager. stable-x86_64-pc-windows-gnu stable-x86_64-pc-windows-msvc /* MQTT (over TCP) Example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include <stdio.h> #include <stdint.h> #include <stddef.h> #include <string.h> #include "esp_wifi.h" #include "esp_system.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_netif.h" #include "protocol_examples_common.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" #include "lwip/sockets.h" #include "lwip/dns.h" #include "lwip/netdb.h" #include "esp_log.h" #include "mqtt_client.h" #include "ssd1366.h" #include "font8x8_basic.h" #define SDA_PIN GPIO_NUM_19 #define SCL_PIN GPIO_NUM_20 static const char *TAG = "mqtt_example"; void i2c_master_init() { i2c_config_t i2c_config = { .mode = I2C_MODE_MASTER, .sda_io_num = SDA_PIN, .scl_io_num = SCL_PIN, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = 100000, .clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL }; i2c_param_config(I2C_NUM_0, &i2c_config); i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); } void ssd1306_init() { esp_err_t espRc; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 向 I2C 总线发送启动信号,表示一个新的传输事务即将开始。 i2c_master_start(cmd); // 写入一个字节到 I2C 总线。这里使用 OLED 模块的 I2C 地址,左移一位并加上写入标志,指示写入操作 i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); // 写入 OLED 控制命令流的字节,表示后续的字节是控制命令。 i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); // 写入 OLED 控制命令,设置充电泵 i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true); // 写入参数字节 i2c_master_write_byte(cmd, 0x14, true); // 写入 OLED 控制命令,设置段重映射,即左右反转 i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // reverse left-right mapping // 写入 OLED 控制命令,设置行扫描模式,即上下反转 i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // reverse up-bottom mapping // 写入 OLED 控制命令,打开 OLED 显示 i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true); // 向 I2C 总线发送停止信号,表示传输事务结束。 i2c_master_stop(cmd); // 执行 I2C 命令序列,将前面构建的命令发送到 I2C 总线上。返回的 espRc 变量会保存执行结果。 espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); if (espRc == ESP_OK) { ESP_LOGI(tag, "OLED configured successfully"); } else { ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc); } // 释放创建的 I2C 命令句柄,以便后续的使用 i2c_cmd_link_delete(cmd); } void task_ssd1306_display_text(void *arg_text) { char *text = (char *)arg_text; uint8_t text_len = strlen(text); i2c_cmd_handle_t cmd; uint8_t cur_page = 0; // 重置起始位置 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); i2c_master_write_byte(cmd, 0x00, true); // reset column i2c_master_write_byte(cmd, 0x10, true); i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); for (uint8_t i = 0; i < text_len; i++) { if (text[i] == '\n') { // 换行 cur_page++; if (cur_page >= 8) { break; // 显示完整文本,超出屏幕范围,退出 } cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); i2c_master_write_byte(cmd, 0x00, true); // reset column i2c_master_write_byte(cmd, 0x10, true); i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // increment page i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); } else { // 显示字符 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); i2c_master_write(cmd, font8x8_basic_tr[(uint8_t)text[i]], 8, true); i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); } } vTaskDelete(NULL); } void generate_string(int columns, int newlines, char* ret) { char buffer[columns*newlines+1]; int j=0; for(int page=0;page<newlines;page++){ for(int i=0;i<columns;i++){ buffer[j] = ' '; j++; } buffer[j]='\n'; j++; } buffer[j] = '\0'; strcpy(ret, buffer); } static void log_error_if_nonzero(const char *message, int error_code) { if (error_code != 0) { ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code); } } /* * [url=home.php?mod=space&uid=159083]@brief[/url] Event handler registered to receive MQTT events * * This function is called by the MQTT client event loop. * * @param handler_args user data registered to the event. * @param base Event base for the handler(always MQTT Base in this example). * @param event_id The id for the received event. * @param event_data The data for the event, esp_mqtt_event_handle_t. */ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id); esp_mqtt_event_handle_t event = event_data; esp_mqtt_client_handle_t client = event->client; int msg_id; switch ((esp_mqtt_event_id_t)event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); msg_id = esp_mqtt_client_publish(client, "/topic/qos1", "data_3", 0, 1, 0); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); break; case MQTT_EVENT_SUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); break; case MQTT_EVENT_UNSUBSCRIBED: ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_PUBLISHED: ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); break; case MQTT_EVENT_DATA: ESP_LOGI(TAG, "MQTT_EVENT_DATA"); printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); printf("DATA=%.*s\r\n", event->data_len, event->data); break; case MQTT_EVENT_ERROR: ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err); log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err); log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno); ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno)); } break; default: ESP_LOGI(TAG, "Other event id:%d", event->event_id); break; } } static void mqtt_app_start(void) { esp_mqtt_client_config_t mqtt_cfg = { .broker.address.uri = CONFIG_BROKER_URL, }; #if CONFIG_BROKER_URL_FROM_STDIN char line[128]; if (strcmp(mqtt_cfg.broker.address.uri, "FROM_STDIN") == 0) { int count = 0; printf("Please enter url of mqtt broker\n"); while (count < 128) { int c = fgetc(stdin); if (c == '\n') { line[count] = '\0'; break; } else if (c > 0 && c < 127) { line[count] = c; ++count; } vTaskDelay(10 / portTICK_PERIOD_MS); } mqtt_cfg.broker.address.uri = line; printf("Broker url: %s\n", line); } else { ESP_LOGE(TAG, "Configuration mismatch: wrong broker url"); abort(); } #endif /* CONFIG_BROKER_URL_FROM_STDIN */ esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); /* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */ esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL); esp_mqtt_client_start(client); } void app_main(void) { i2c_master_init(); ssd1306_init(); // 清屏操作 const int columns = 16; const int page = 8; char space[columns*page+1]; generate_string(columns, page, space); // 清除屏幕内容 xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *)space, 6, NULL); // 间隔一会防止进程有干扰 vTaskDelay(500/portTICK_PERIOD_MS); xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *) "Hello world!\nMulitine is OK!\nAnother line", 6, NULL); ESP_LOGI(TAG, "[APP] Startup.."); ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size()); ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); esp_log_level_set("*", ESP_LOG_INFO); esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE); esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE); esp_log_level_set("transport_base", ESP_LOG_VERBOSE); esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); esp_log_level_set("transport", ESP_LOG_VERBOSE); esp_log_level_set("outbox", ESP_LOG_VERBOSE); ESP_ERROR_CHECK(nvs_flash_init()); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. * Read "Establishing Wi-Fi or Ethernet Connection" section in * examples/protocols/README.md for more information about this function. */ ESP_ERROR_CHECK(example_connect()); mqtt_app_start(); } 使得程序可以显示,演示进入esp_deep_sleep_start()模式。  测试过程 将电源调试到3.3V和3.0V测试。   连接测试   系统进入deep_sleep模式,但是可以发现,屏幕显示好像没有变化,但是ping主机确无法通过了。   使用短路引脚无法唤醒。只能重新上电。

  • 2024-06-07
  • 发表了主题帖: 【FireBeetle 2 ESP32 C6】I2C接口的通讯测试与GUI显示

    测试介绍 ESP32C6的IIC和S3的系列没有太大的变化,乐鑫团队的编程对于ESP32的系列是相似的。本次测试原本使用I2C接口的SSD1306显示屏作为测试目标。原本计划使用GC9A01,但是发现esp32C6没有GUI外设,而且SPI的接口内存也不足,后来改为ssd1306了。   OLED 屏的接口可以是SPI或IIC,本次测试使用的是IIC接口,开发板使用的是FireBeetle 2 ESP32C6 开发板,使用的引脚为IO20,IO19,使用I2C控制器,速率100Khz   硬件连接 IO20 <-------------> SCL , SSD1306 SCL IO19 <-------------> SDA , SSD1306 SDA SSD1306的电源供电为VCC = 3.3V。 测试程序与过程 使用面包板将开发板和SSD1306连接,然后将C:\Espressif\frameworks\esp-idf-v5.2.1\examples\get-started\hello_world,的helloworld的测试程序拷贝到测试目录。 将测试程序main.c修改如下: #include <string.h> #include "driver/gpio.h" #include "driver/i2c.h" #include "esp_err.h" #include "esp_log.h" #include "freertos/task.h" #include "sdkconfig.h" #include "ssd1366.h" #include "font8x8_basic.h" #define SDA_PIN GPIO_NUM_19 #define SCL_PIN GPIO_NUM_20 #define tag "SSD1306" void i2c_master_init() { i2c_config_t i2c_config = { .mode = I2C_MODE_MASTER, .sda_io_num = SDA_PIN, .scl_io_num = SCL_PIN, .sda_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE, .master.clk_speed = 100000, .clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL }; i2c_param_config(I2C_NUM_0, &i2c_config); i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0); } void ssd1306_init() { esp_err_t espRc; i2c_cmd_handle_t cmd = i2c_cmd_link_create(); // 向 I2C 总线发送启动信号,表示一个新的传输事务即将开始。 i2c_master_start(cmd); // 写入一个字节到 I2C 总线。这里使用 OLED 模块的 I2C 地址,左移一位并加上写入标志,指示写入操作 i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); // 写入 OLED 控制命令流的字节,表示后续的字节是控制命令。 i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); // 写入 OLED 控制命令,设置充电泵 i2c_master_write_byte(cmd, OLED_CMD_SET_CHARGE_PUMP, true); // 写入参数字节 i2c_master_write_byte(cmd, 0x14, true); // 写入 OLED 控制命令,设置段重映射,即左右反转 i2c_master_write_byte(cmd, OLED_CMD_SET_SEGMENT_REMAP, true); // reverse left-right mapping // 写入 OLED 控制命令,设置行扫描模式,即上下反转 i2c_master_write_byte(cmd, OLED_CMD_SET_COM_SCAN_MODE, true); // reverse up-bottom mapping // 写入 OLED 控制命令,打开 OLED 显示 i2c_master_write_byte(cmd, OLED_CMD_DISPLAY_ON, true); // 向 I2C 总线发送停止信号,表示传输事务结束。 i2c_master_stop(cmd); // 执行 I2C 命令序列,将前面构建的命令发送到 I2C 总线上。返回的 espRc 变量会保存执行结果。 espRc = i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); if (espRc == ESP_OK) { ESP_LOGI(tag, "OLED configured successfully"); } else { ESP_LOGE(tag, "OLED configuration failed. code: 0x%.2X", espRc); } // 释放创建的 I2C 命令句柄,以便后续的使用 i2c_cmd_link_delete(cmd); } void task_ssd1306_display_text(void *arg_text) { char *text = (char *)arg_text; uint8_t text_len = strlen(text); i2c_cmd_handle_t cmd; uint8_t cur_page = 0; // 重置起始位置 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); i2c_master_write_byte(cmd, 0x00, true); // reset column i2c_master_write_byte(cmd, 0x10, true); i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // reset page i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); for (uint8_t i = 0; i < text_len; i++) { if (text[i] == '\n') { // 换行 cur_page++; if (cur_page >= 8) { break; // 显示完整文本,超出屏幕范围,退出 } cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_CMD_STREAM, true); i2c_master_write_byte(cmd, 0x00, true); // reset column i2c_master_write_byte(cmd, 0x10, true); i2c_master_write_byte(cmd, 0xB0 | cur_page, true); // increment page i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); } else { // 显示字符 cmd = i2c_cmd_link_create(); i2c_master_start(cmd); i2c_master_write_byte(cmd, (OLED_I2C_ADDRESS << 1) | I2C_MASTER_WRITE, true); i2c_master_write_byte(cmd, OLED_CONTROL_BYTE_DATA_STREAM, true); i2c_master_write(cmd, font8x8_basic_tr[(uint8_t)text[i]], 8, true); i2c_master_stop(cmd); i2c_master_cmd_begin(I2C_NUM_0, cmd, 10 / portTICK_PERIOD_MS); i2c_cmd_link_delete(cmd); } } vTaskDelete(NULL); } void generate_string(int columns, int newlines, char* ret) { char buffer[columns*newlines+1]; int j=0; for(int page=0;page<newlines;page++){ for(int i=0;i<columns;i++){ buffer[j] = ' '; j++; } buffer[j]='\n'; j++; } buffer[j] = '\0'; strcpy(ret, buffer); } void app_main(void) { i2c_master_init(); ssd1306_init(); // 清屏操作 const int columns = 16; const int page = 8; char space[columns*page+1]; generate_string(columns, page, space); // 清除屏幕内容 xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *)space, 6, NULL); // 间隔一会防止进程有干扰 vTaskDelay(500/portTICK_PERIOD_MS); xTaskCreate(&task_ssd1306_display_text, "ssd1306_display_text", 2048, (void *) "Hello world!\nMulitine is OK!\nAnother line", 6, NULL); while(1){ vTaskDelay(1); } } 测试程序,还有一部分是字体程序。 /* * font8x8_basic.h * * Created on: 2017/05/03 * Author: yanbe */ #ifndef MAIN_FONT8X8_BASIC_H_ #define MAIN_FONT8X8_BASIC_H_ /* Constant: font8x8_basic_tr Contains an 90 digree transposed 8x8 font map for unicode points U+0000 - U+007F (basic latin) To make it easy to use with SSD1306's GDDRAM mapping and API, this constant is an 90 degree transposed. The original version written by Marcel Sondaar is availble at: https://github.com/dhepper/font8x8/blob/master/font8x8_basic.h Conversion is done via following procedure: for (int code = 0; code < 128; code++) { uint8_t trans[8]; for (int w = 0; w < 8; w++) { trans[w] = 0x00; for (int b = 0; b < 8; b++) { trans[w] |= ((font8x8_basic[code][b] & (1 << w)) >> w) << b; } } for (int w = 0; w < 8; w++) { if (w == 0) { printf(" { "); } printf("0x%.2X", trans[w]); if (w < 7) { printf(", "); } if (w == 7) { printf(" }, // U+00%.2X (%c)\n", code, code); } } } */ uint8_t font8x8_basic_tr[128][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0000 (nul) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0001 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0002 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0003 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0004 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0005 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0006 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0007 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0008 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0009 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000A { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000B { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000C { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000E { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+000F { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0010 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0011 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0012 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0013 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0014 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0015 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0016 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0017 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0018 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0019 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001A { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001B { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001C { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001E { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+001F { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0020 (space) { 0x00, 0x00, 0x06, 0x5F, 0x5F, 0x06, 0x00, 0x00 }, // U+0021 (!) { 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x00 }, // U+0022 (") { 0x14, 0x7F, 0x7F, 0x14, 0x7F, 0x7F, 0x14, 0x00 }, // U+0023 (#) { 0x24, 0x2E, 0x6B, 0x6B, 0x3A, 0x12, 0x00, 0x00 }, // U+0024 ($) { 0x46, 0x66, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x00 }, // U+0025 (%) { 0x30, 0x7A, 0x4F, 0x5D, 0x37, 0x7A, 0x48, 0x00 }, // U+0026 (&) { 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, // U+0027 (') { 0x00, 0x1C, 0x3E, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+0028 (() { 0x00, 0x41, 0x63, 0x3E, 0x1C, 0x00, 0x00, 0x00 }, // U+0029 ()) { 0x08, 0x2A, 0x3E, 0x1C, 0x1C, 0x3E, 0x2A, 0x08 }, // U+002A (*) { 0x08, 0x08, 0x3E, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+002B (+) { 0x00, 0x80, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002C (,) { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00 }, // U+002D (-) { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }, // U+002E (.) { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00 }, // U+002F (/) { 0x3E, 0x7F, 0x71, 0x59, 0x4D, 0x7F, 0x3E, 0x00 }, // U+0030 (0) { 0x40, 0x42, 0x7F, 0x7F, 0x40, 0x40, 0x00, 0x00 }, // U+0031 (1) { 0x62, 0x73, 0x59, 0x49, 0x6F, 0x66, 0x00, 0x00 }, // U+0032 (2) { 0x22, 0x63, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0033 (3) { 0x18, 0x1C, 0x16, 0x53, 0x7F, 0x7F, 0x50, 0x00 }, // U+0034 (4) { 0x27, 0x67, 0x45, 0x45, 0x7D, 0x39, 0x00, 0x00 }, // U+0035 (5) { 0x3C, 0x7E, 0x4B, 0x49, 0x79, 0x30, 0x00, 0x00 }, // U+0036 (6) { 0x03, 0x03, 0x71, 0x79, 0x0F, 0x07, 0x00, 0x00 }, // U+0037 (7) { 0x36, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00, 0x00 }, // U+0038 (8) { 0x06, 0x4F, 0x49, 0x69, 0x3F, 0x1E, 0x00, 0x00 }, // U+0039 (9) { 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003A (:) { 0x00, 0x80, 0xE6, 0x66, 0x00, 0x00, 0x00, 0x00 }, // U+003B (;) { 0x08, 0x1C, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00 }, // U+003C (<) { 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x00, 0x00 }, // U+003D (=) { 0x00, 0x41, 0x63, 0x36, 0x1C, 0x08, 0x00, 0x00 }, // U+003E (>) { 0x02, 0x03, 0x51, 0x59, 0x0F, 0x06, 0x00, 0x00 }, // U+003F (?) { 0x3E, 0x7F, 0x41, 0x5D, 0x5D, 0x1F, 0x1E, 0x00 }, // U+0040 (@) { 0x7C, 0x7E, 0x13, 0x13, 0x7E, 0x7C, 0x00, 0x00 }, // U+0041 (A) { 0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00 }, // U+0042 (B) { 0x1C, 0x3E, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00 }, // U+0043 (C) { 0x41, 0x7F, 0x7F, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+0044 (D) { 0x41, 0x7F, 0x7F, 0x49, 0x5D, 0x41, 0x63, 0x00 }, // U+0045 (E) { 0x41, 0x7F, 0x7F, 0x49, 0x1D, 0x01, 0x03, 0x00 }, // U+0046 (F) { 0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00 }, // U+0047 (G) { 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, 0x00, 0x00 }, // U+0048 (H) { 0x00, 0x41, 0x7F, 0x7F, 0x41, 0x00, 0x00, 0x00 }, // U+0049 (I) { 0x30, 0x70, 0x40, 0x41, 0x7F, 0x3F, 0x01, 0x00 }, // U+004A (J) { 0x41, 0x7F, 0x7F, 0x08, 0x1C, 0x77, 0x63, 0x00 }, // U+004B (K) { 0x41, 0x7F, 0x7F, 0x41, 0x40, 0x60, 0x70, 0x00 }, // U+004C (L) { 0x7F, 0x7F, 0x0E, 0x1C, 0x0E, 0x7F, 0x7F, 0x00 }, // U+004D (M) { 0x7F, 0x7F, 0x06, 0x0C, 0x18, 0x7F, 0x7F, 0x00 }, // U+004E (N) { 0x1C, 0x3E, 0x63, 0x41, 0x63, 0x3E, 0x1C, 0x00 }, // U+004F (O) { 0x41, 0x7F, 0x7F, 0x49, 0x09, 0x0F, 0x06, 0x00 }, // U+0050 (P) { 0x1E, 0x3F, 0x21, 0x71, 0x7F, 0x5E, 0x00, 0x00 }, // U+0051 (Q) { 0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00 }, // U+0052 (R) { 0x26, 0x6F, 0x4D, 0x59, 0x73, 0x32, 0x00, 0x00 }, // U+0053 (S) { 0x03, 0x41, 0x7F, 0x7F, 0x41, 0x03, 0x00, 0x00 }, // U+0054 (T) { 0x7F, 0x7F, 0x40, 0x40, 0x7F, 0x7F, 0x00, 0x00 }, // U+0055 (U) { 0x1F, 0x3F, 0x60, 0x60, 0x3F, 0x1F, 0x00, 0x00 }, // U+0056 (V) { 0x7F, 0x7F, 0x30, 0x18, 0x30, 0x7F, 0x7F, 0x00 }, // U+0057 (W) { 0x43, 0x67, 0x3C, 0x18, 0x3C, 0x67, 0x43, 0x00 }, // U+0058 (X) { 0x07, 0x4F, 0x78, 0x78, 0x4F, 0x07, 0x00, 0x00 }, // U+0059 (Y) { 0x47, 0x63, 0x71, 0x59, 0x4D, 0x67, 0x73, 0x00 }, // U+005A (Z) { 0x00, 0x7F, 0x7F, 0x41, 0x41, 0x00, 0x00, 0x00 }, // U+005B ([) { 0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x00 }, // U+005C (\) { 0x00, 0x41, 0x41, 0x7F, 0x7F, 0x00, 0x00, 0x00 }, // U+005D (]) { 0x08, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // U+005E (^) { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }, // U+005F (_) { 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00 }, // U+0060 (`) { 0x20, 0x74, 0x54, 0x54, 0x3C, 0x78, 0x40, 0x00 }, // U+0061 (a) { 0x41, 0x7F, 0x3F, 0x48, 0x48, 0x78, 0x30, 0x00 }, // U+0062 (b) { 0x38, 0x7C, 0x44, 0x44, 0x6C, 0x28, 0x00, 0x00 }, // U+0063 (c) { 0x30, 0x78, 0x48, 0x49, 0x3F, 0x7F, 0x40, 0x00 }, // U+0064 (d) { 0x38, 0x7C, 0x54, 0x54, 0x5C, 0x18, 0x00, 0x00 }, // U+0065 (e) { 0x48, 0x7E, 0x7F, 0x49, 0x03, 0x02, 0x00, 0x00 }, // U+0066 (f) { 0x98, 0xBC, 0xA4, 0xA4, 0xF8, 0x7C, 0x04, 0x00 }, // U+0067 (g) { 0x41, 0x7F, 0x7F, 0x08, 0x04, 0x7C, 0x78, 0x00 }, // U+0068 (h) { 0x00, 0x44, 0x7D, 0x7D, 0x40, 0x00, 0x00, 0x00 }, // U+0069 (i) { 0x60, 0xE0, 0x80, 0x80, 0xFD, 0x7D, 0x00, 0x00 }, // U+006A (j) { 0x41, 0x7F, 0x7F, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+006B (k) { 0x00, 0x41, 0x7F, 0x7F, 0x40, 0x00, 0x00, 0x00 }, // U+006C (l) { 0x7C, 0x7C, 0x18, 0x38, 0x1C, 0x7C, 0x78, 0x00 }, // U+006D (m) { 0x7C, 0x7C, 0x04, 0x04, 0x7C, 0x78, 0x00, 0x00 }, // U+006E (n) { 0x38, 0x7C, 0x44, 0x44, 0x7C, 0x38, 0x00, 0x00 }, // U+006F (o) { 0x84, 0xFC, 0xF8, 0xA4, 0x24, 0x3C, 0x18, 0x00 }, // U+0070 (p) { 0x18, 0x3C, 0x24, 0xA4, 0xF8, 0xFC, 0x84, 0x00 }, // U+0071 (q) { 0x44, 0x7C, 0x78, 0x4C, 0x04, 0x1C, 0x18, 0x00 }, // U+0072 (r) { 0x48, 0x5C, 0x54, 0x54, 0x74, 0x24, 0x00, 0x00 }, // U+0073 (s) { 0x00, 0x04, 0x3E, 0x7F, 0x44, 0x24, 0x00, 0x00 }, // U+0074 (t) { 0x3C, 0x7C, 0x40, 0x40, 0x3C, 0x7C, 0x40, 0x00 }, // U+0075 (u) { 0x1C, 0x3C, 0x60, 0x60, 0x3C, 0x1C, 0x00, 0x00 }, // U+0076 (v) { 0x3C, 0x7C, 0x70, 0x38, 0x70, 0x7C, 0x3C, 0x00 }, // U+0077 (w) { 0x44, 0x6C, 0x38, 0x10, 0x38, 0x6C, 0x44, 0x00 }, // U+0078 (x) { 0x9C, 0xBC, 0xA0, 0xA0, 0xFC, 0x7C, 0x00, 0x00 }, // U+0079 (y) { 0x4C, 0x64, 0x74, 0x5C, 0x4C, 0x64, 0x00, 0x00 }, // U+007A (z) { 0x08, 0x08, 0x3E, 0x77, 0x41, 0x41, 0x00, 0x00 }, // U+007B ({) { 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00 }, // U+007C (|) { 0x41, 0x41, 0x77, 0x3E, 0x08, 0x08, 0x00, 0x00 }, // U+007D (}) { 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00 }, // U+007E (~) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // U+007F }; #endif /* MAIN_FONT8X8_BASIC_H_ */ 这是一个头文件程序。 设置设置目标。编译、烧写、运行 idf.py set-target esp32c6 idf.py menuconfig idf.py build idf.py -p COM5 flash idf.py -p COM5 monitor 测试过程 控制台显示   测试程序照片      

  • 2024-06-03
  • 回复了主题帖: 【NUCLEO-U083RC】DAC输出与内置比较器测试

    本次测试使用的源代码,

  • 发表了主题帖: 【NUCLEO-U083RC】DAC输出与内置比较器测试

    测试介绍 这次测试是一次复合测试,完成了DAC和COMP两个测试,该测试是测试STM32U083的DAC和内部的比较器测试,测试通过DAC生成电压信号,然后将电压信号引入MCU的内部运放电路,通过设置比较条件观察测试结果。 硬件使用STM32U083 MCU的NUCLEO-U083RC开发板,需要使用MCU的DAC1外设,COMP1外设。LED4作为比较指示,LED4亮标志有中断发生。 使用BUTTON按键,改变DAC输出的值。 将PA1和PA4使用导线连接起来。按压BUTTON改变设置,直到LED4亮起。   硬件连接与设置 DAC设置:外设:DAC1,输出方式:外部输出 COMP设置:外设:COMP1,比较电压:1/2内部参考源,中断打开。 COMP1设置   DAC1设置   BSP设置,使用LED4和按键BUTTON1,打开按键的中断     测试程序与工作原理 COMP比较器,的比较输入是物理引脚PA1。比较参考:内部参考源和外部参考源,也可以是DAC的通道,比较输出结果:可以使用查询方式,也可以使用中断方式,本测试使用中断方式,同时也可以使用输出到物理引脚,这种方式不需要MCU的参与,响应速度非常快。   测试中使用了BUTTON1按键,启用了按键的中断模式,在中断中设置UserButtonStatus值,来驱动测试。 /**   * @brief   EXTI line detection callbacks   * @param  GPIO_Pin: Specifies the pins connected EXTI line   * @retval None   */ void BSP_PB_Callback(Button_TypeDef Button) {       UserButtonStatus = 1;   } 主程序中查询UserButtonStatus值修改DAC的输出电压。 if (UserButtonStatus == 1)     {                                           UserDACValue = (UserDACValue + 10) % 4096;                      if (HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_8B_R, UserDACValue) != HAL_OK)                      {                                    /* Setting value Error */                                    Error_Handler();                      }                      UserButtonStatus=0;               } 整个程序不是非常复杂。 比较器中断程序。 /**   * @brief  Comparator interruption callback   * @note   This function is called when comparator threshold is triggered.   * @param  hcomp  COMP handle   * @retval None   */ void HAL_COMP_TriggerCallback(COMP_HandleTypeDef *hcomp) {   /* Set LED state in function of comparator output level */   if (HAL_COMP_GetOutputLevel(hcomp) == COMP_OUTPUT_LEVEL_HIGH)   {     BSP_LED_Off(LED4);   }   else   {     BSP_LED_On(LED4);   } }   测试过程 将引脚PA1和PA4连接,板子上电   开始LED4是熄灭状态。 开始按压BOTTON1,连续按压几次。   LED4亮起,说明中断起作用了。 测试总结 这是第一次测试COMP输出没有经验,整个测试其实是分开做的,开始参考DAC_SimpleConversion例程,调试DAC输出。然后驱动按键,在测试过程中,按键的中断过程怎么也起做,但是中断程序能进入,这让我感到奇怪,后来发现是BSP版本问题,使用正确的版本之后完成。主要是:BSP_PB_Callback文件名称造成的,注意使用BSP驱动里声明的名称。 按键调试好之后,调试COMP的程序,参考了COMP_CompareGpioVsVrefInt_IT程序,整个过程用了2天的时间,才把COMP搞明白了。  

  • 回复了主题帖: 【NUCLEO-U083RC】SPI总线GC9A01屏

    lugl4313820 发表于 2024-6-2 21:22 本次测试屏的显示刷新速率有点慢。是硬件spi传输吗? 不是SPI的问题是,刷新方案问题。我正在解决。

  • 2024-06-02
  • 发表了主题帖: 【NUCLEO-U083RC】SPI总线GC9A01屏

    测试介绍 该测试是测试STM32U083的SPI接口测试,测试使用的是GC9A01屏,该屏为SPI接口,   SPI接口除电源外:有5个引脚,SPI:CLK、MOSI,DC,CS、RESET引脚。 硬件使用STM32U083 MCU的NUCLEO-U083RC开发板,需要使用SPI外设,还有2个GPIO输出,CS引脚未使用。   测试的过程,是向屏幕输出不同色彩的图案。 硬件连接 外设SPI:SPI1,数据格式8bit,时钟分频:SCLK/2,速率:8Mbit/S,SPI_CLK:PB3,SPI_MOSI:PB5,模式使用:SPI MODE MASTER 传输模式 DC命令/数据:GPIO PB4 REST:GPIO PB10 测试设置 SPI设置,SPI1,MASTER 传输模式   GPIO设置     测试程序 程序的主要驱动为GC9A01.C程序。 引用图形程序 /* USER CODE END WHILE */     color[0] = 0xFF;     color[1] = 0xFF;     for (int x = 0; x < 240; x++) {         for (int y = 0; y < 240; y++) {             if (x < y) {                 color[2] = 0xFF;             } else {                 color[2] = 0x00;             }             if (x == 0 && y == 0) {                 GC9A01_write(color, sizeof(color));             } else {                 GC9A01_write_continue(color, sizeof(color));             }         }     }               HAL_Delay(100);               float frequency = 0.026;     for (int x = 0; x < 240; x++) {         color[0] = sin(frequency*x + 0) * 127 + 128;         color[1] = sin(frequency*x + 2) * 127 + 128;         color[2] = sin(frequency*x + 4) * 127 + 128;         for (int y = 0; y < 240; y++) {             if (x == 0 && y == 0) {                 GC9A01_write(color, sizeof(color));             } else {                 GC9A01_write_continue(color, sizeof(color));             }         }     }                             // Checkerboard     for (int x = 0; x < 240; x++) {         for (int y = 0; y < 240; y++) {             if ((x / 10) % 2 ==  (y / 10) % 2) {                 color[0] = 0xFF;                 color[1] = 0xFF;                 color[2] = 0xFF;             } else {                 color[0] = 0x00;                 color[1] = 0x00;                 color[2] = 0x00;             }             if (x == 0 && y == 0) {                 GC9A01_write(color, sizeof(color));             } else {                 GC9A01_write_continue(color, sizeof(color));             }         }     }                             color[0] = 0xFF;     for (int x = 0; x < 240; x++) {         for (int y = 0; y < 240; y++) {             if ((x >= 1*48 && x < 4*48 && y >= 2*48 && y < 3*48) ||                 (x >= 2*48 && x < 3*48 && y >= 1*48 && y < 4*48)) {                 color[1] = 0xFF;                 color[2] = 0xFF;             } else {                 color[1] = 0x00;                 color[2] = 0x00;             }             if (x == 0 && y == 0) {                 GC9A01_write(color, sizeof(color));             } else {                 GC9A01_write_continue(color, sizeof(color));             }         }     }               GC9A01_write_command(0x20);     测试过程 程序烧入MCU中  本次测试屏的显示刷新速率有点慢。    

  • 发表了主题帖: 【NUCLEO-U083RC】ADC软件触发DMA转换和串口通讯测试

    测试介绍 本次测试为STM32U083的ADC性能和DMA转换数据方式。STM32U083带有一个12位ADC,并且数据转换方式可以通过没有MCU参与的DMA方式。带有7个异步/同步uart串行接口,3个是低功耗模式,4个为普通模式。测试使用UART2输出测试ADC转化数据。LED4作为故障指示。当系统出现故障时LED4将常亮。 测试硬件连接 ADC设置:转换外设:ADC1,通道:IN4通道,采样时钟:系统时钟源SYSCLK/4分频,引脚:PA0,DMA支持:开,转换触发模式:SW软件循环模式,DMA中断打开。   DMA设置:外设:DMA1,循环模式传输数组模式,数据宽度:16bit,外设到内存。 UART设置:外设:UART2,速率:115200,数据长度:8bit、停止位:1、校验:无校验 使用SW触发转换单通道,单通道输出引脚使用:PA0引脚。UART引脚:PA2 UART2_TX,PA3 UART2_RX   测试设置 系统时钟设置:   ADC时钟测试SYSCLK/4分频。 ADC1设置:   ADC外设与DMA中断测试     USART2设置:   设置:115200、8bit、stop 1bit、NONE DMA1设置:     测试程序 开始,使用自定义的项目进行测试,但是程序总是出现故障,在ADC_Activate()函数的LL_ADC_Enable(ADC1);这条处跳转到故障循环里。后来又将设置程序另存为SWADC生成程序,故障依旧没有排除,后来,将ADC_SingleConversion_TriggerSW_DMA_Init例程的代码改造后才成功,这次USART使用的是LL库,而不是HAL库,HAL库无法调通,原因不明遂放弃HAL。后来改成LL库测试通过。   程序分为三个部分:自动生成的初始化程序,DMA中断程序,采样程序。 /**   * @brief This function handles DMA1 channel 1 interrupt.   */ void DMA1_Channel1_IRQHandler(void) {   /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */   /* Check whether DMA transfer complete caused the DMA interruption */   if(LL_DMA_IsActiveFlag_TC1(DMA1) == 1)   {     /* Clear flag DMA transfer complete */     LL_DMA_ClearFlag_TC1(DMA1);         /* Call interruption treatment function */     AdcDmaTransferComplete_Callback();   }     /* USER CODE END DMA1_Channel1_IRQn 0 */     /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */     /* Check whether DMA transfer error caused the DMA interruption */   if(LL_DMA_IsActiveFlag_TE1(DMA1) == 1)   {     /* Clear flag DMA transfer error */     LL_DMA_ClearFlag_TE1(DMA1);         /* Call interruption treatment function */     AdcDmaTransferError_Callback();   }     /* USER CODE END DMA1_Channel1_IRQn 1 */ }   /**   * @brief This function handles ADC1, COMP1 and COMP2 Interrupts (combined with EXTI 17 & 18).   */ void ADC_COMP1_2_IRQHandler(void) {   /* USER CODE BEGIN ADC_COMP1_2_IRQn 0 */ /* Check whether ADC group regular overrun caused the ADC interruption */   if(LL_ADC_IsActiveFlag_OVR(ADC1) != 0)   {     /* Clear flag ADC group regular overrun */     LL_ADC_ClearFlag_OVR(ADC1);       /* Call interruption treatment function */     AdcGrpRegularOverrunError_Callback();   }   /* USER CODE END ADC_COMP1_2_IRQn 0 */     /* USER CODE BEGIN ADC_COMP1_2_IRQn 1 */     /* USER CODE END ADC_COMP1_2_IRQn 1 */ }   /* USER CODE BEGIN 1 */   /* USER CODE END 1 */   主要是两个中断函数。void ADC_COMP1_2_IRQHandler(void)和void DMA1_Channel1_IRQHandler(void) 采样程序     /* Start ADC group regular conversion */     /* Note: Hardware constraint (refer to description of the functions       */     /*       below):                                                          */     /*       On this STM32 series, setting of this feature is conditioned to  */     /*       ADC state:                                                       */     /*       ADC must be enabled without conversion on going on group regular,*/     /*       without ADC disable command on going.                            */     /* Note: In this example, all these checks are not necessary but are      */     /*       implemented anyway to show the best practice usages              */     /*       corresponding to reference manual procedure.                     */     /*       Software can be optimized by removing some of these checks, if   */     /*       they are not relevant considering previous settings and actions  */     /*       in user application.                                             */     if ((LL_ADC_IsEnabled(ADC1) == 1)               &&         (LL_ADC_IsDisableOngoing(ADC1) == 0)        &&         (LL_ADC_REG_IsConversionOngoing(ADC1) == 0)   )     {       LL_ADC_REG_StartConversion(ADC1);     }     else     {       /* Error: ADC conversion start could not be performed */       Error_Handler();     }       /* Toggle LED at each ADC conversion */     LED_On();     LL_mDelay(LED_BLINK_SLOW);     LED_Off();     LL_mDelay(LED_BLINK_SLOW);       /* Note: ADC group regular conversions data are stored into array         */     /*       "uhADCxConvertedData"                                            */     /*       (for debug: see variable content into watch window).             */       /* Note: ADC conversion data are computed to physical values              */     /*       into array "uhADCxConvertedData_Voltage_mVolt" using             */     /*       ADC LL driver helper macro "__LL_ADC_CALC_DATA_TO_VOLTAGE()"     */     /*       (for debug: see variable content with debugger)                  */       /* If ADC conversions and DMA transfer are completed, then process data */     if(ubDmaTransferStatus == 1)     {       /* Update status variable of DMA transfer */       ubDmaTransferStatus = 0;         /* Computation of ADC conversions raw data to physical values          using LL ADC driver helper macro. */                            for (tmp_index = 0; tmp_index < ADC_CONVERTED_DATA_BUFFER_SIZE; tmp_index++)       {                             tmp_value = __LL_ADC_CALC_DATA_TO_VOLTAGE(VDDA_APPLI, uhADCxConvertedData[tmp_index], LL_ADC_RESOLUTION_12B);                             vf = (float)tmp_value /1000;                             memset(buffer,0,20);                        snprintf(buffer,20,"Value= %f\n\r",vf);                                                  tmp_index = 0;                             while(buffer[tmp_index] !=  '\0' && tmp_index < 20)                             {                                     while(!LL_USART_IsActiveFlag_TXE(USART2));                                     LL_USART_TransmitData8(USART2,(uint8_t )buffer[tmp_index]);                                     tmp_index++;                             }         }                        LED_Toggle();       LL_mDelay(500); /* Delay to highlight toggle sequence */     }       /* USER CODE END WHILE */       /* USER CODE BEGIN 3 */   } 关键是LL_ADC_REG_StartConversion(ADC1);函数的调用条件,调用后所有的数据DMA保存到数组uhADCxConvertedData当中。   测试过程 使用过程校准仪,输出1.5V的信号,测试ADC的转换。   测试现场照片。    

  • 2024-06-01
  • 回复了主题帖: 【NUCLEO-U083RC】I2C总线设备的兼容性测试

    配套的sht21程序

  • 发表了主题帖: 【NUCLEO-U083RC】I2C总线设备的兼容性测试

    测试介绍 为了测试STM32U083的I2C性能,本次安排的测试使用sht21作为测试设备。sht21是一款较为流行的空气温湿度传感器,sht21使用I2C总线接口与MCU通讯。该设备的I2C接口较为标准,符合I2C规范。   开发板使用NUCLEO-U083RC,开发板带有4个I2C接口,每个接口均支持I2C Master模式。速度支持,超高速、高速、普通模式。带有7个异步/同步uart串行接口,3个是低功耗模式,4个为普通模式。 测试硬件连接 PC接口使用UART2 接口,数据位:8bit,速率:115200,停止位:1,校验:无 I2C接口,接口:I2C1, 引脚:PB8 SCL,PB9 SDA,速率:100K,地址位:7bit   测试设置:   测试设置,选择开发板类型:NUCLEO-U083RC,资源使用I2C1、usart2、led4资源。 本次测试,使用USART接口输出sht21的测试结果。Led4作为测试运行指示,如果出现错误,程序自动转到LED4常亮状态。程序项目类型使用,keil类型。 测试代码 Sht21的程序驱动代码,由两部分组成,一部分是设置和初始化代码。另一部分是功能代码。 SHT2x_Init(&hi2c1); SHT2x_SetResolution(RES_14_12); 引用代码如下: unsigned char buffer[100] = { 0 }; /* Gets current temperature & relative humidity. */ float cel = SHT2x_GetTemperature(1);   /* Converts temperature to degrees Fahrenheit and Kelvin */ float fah = SHT2x_CelsiusToFahrenheit(cel); float kel = SHT2x_CelsiusToKelvin(cel); float rh = SHT2x_GetRelativeHumidity(1); /* May show warning below. Ignore and proceed. */ printf("%d.%d, %d.%d , %d.%d K, %d.%d%% RH\r\n",        SHT2x_GetInteger(cel), SHT2x_GetDecimal(cel, 1),        SHT2x_GetInteger(fah), SHT2x_GetDecimal(fah, 1),        SHT2x_GetInteger(kel), SHT2x_GetDecimal(kel, 1),        SHT2x_GetInteger(rh), SHT2x_GetDecimal(rh, 1));     测试过程:       从获取数据   和成品的测试相差不大。  

  • 2024-05-28
  • 回复了主题帖: 《Rust实战》书友互动第六集:内存,有啥你不熟悉的吗?

    堆和栈都是内存区域,传统意义的变量其实质是小块内容区域,用来存放数据的区域,变量名称是这段内存区域的地址名称,存放变量的变量就是指针,理解了这一点才可以理解rust中的内存管理,堆和栈是两种使用方法不同的内存区域,堆:是存放全局和动态变量的内存,所以其管理和释放比较复杂,访问操作步骤繁琐,所以就慢。栈是直接分配给函数的区域,可以直接操作。速度就快。可以参考以下视频 【搞清楚内存泄漏-编程基础】

  • 2024-05-27
  • 回复了主题帖: 《Rust实战》书友互动第七集:文件与存储

    rust中的文件操作是一种较为基层的操作,文件的打开和关闭是文件与操作系统打交道的事情,怎么保证在程序操作时,能够保证程序在文件操作失败时,保证程序的控制权

  • 2024-05-19
  • 回复了主题帖: 【NUCLEO-U083RC】EXIT中断测试及功耗测试

    lugl4313820 发表于 2024-5-19 07:16 这是需要手动换档来测试吗?我测试的成绩怎么没有这么优秀呀。 这个和你的用的内容不同而异,我只是使用了最简单的GPIO端口,如果使用更多的外设,需要的功耗一会增加的

  • 2024-05-17
  • 回复了主题帖: 有知道viso绘制原理图的大佬吗

    mryyh 发表于 2024-5-17 14:53 做原理图,还是要用orcad,visio资源不全,还没有电气连接,两个软件都不熟,不如去学习orcad,orcad很容易 ... 我是用来做插画,不是画PCB板子。所以只要能够反应设备就可以了

  • 回复了主题帖: 功率电阻不同公式计算的的功率

    哈哈,沙发正解: 【50毫欧,一端的电压12.6V,流过的电流2.4A】 有这样的电阻么? 回去把初中物理课程重修一下吧。   电压是电阻两端的压降!  

  • 回复了主题帖: 运动控制器方案讨论

    laker2008 发表于 2024-5-15 15:20 额,听起来好专业的东东,没用到过,特意某度了一下是做什么用的,高大上的玩意啊, 不大严格的说:运动控制器是一种专用的plc,plc是专用的mcu系统,plc可以控制的面较宽。运动控制器可以看成是带有运动控制功能的plc。 目前的运动控制器的主要结构是:“电机控制模块+通讯模块”再加增加一个PLC或其它的控制软件。 电机控制模块:驱动模块+MCU控制模块 这种套娃结构就是运动控制器了。 codesys是一套软件系统,系统实现了PLC的全套软件,包括PC机的编程软件和MCU系统的控制软件。codesys遵守IEC61131-3的规范,codesys也接受定制。但是价格较贵,国内的很多PLC企业采用该系统,所以编程特色和功能有较重的同质化趋势。

  • 2024-05-16
  • 回复了主题帖: 有知道viso绘制原理图的大佬吗

    找到了Paul Herber - Electrical shapes for Microsoft Visio可是这个需要银子地

  • 发表了主题帖: 有知道viso绘制原理图的大佬吗

    这是网上有用viso画的原理图,图中的Vdd符号可以确定不是viso自带的,好像这个库“from netter.vss”,但是我从C*DN和EE上下载的文件我的2019都无法安装。请问各位有用于2019版的文件下载的url吗  

  • 回复了主题帖: SPI通信的疑问

    1、这种电路是通过CS(片选),实现各设备通讯互不干扰的。 2、这种电路的缺点是,需要各种设备的通讯一直,理论上可以不一直,但是编程麻烦,例如:flash和oled屏共享spi bus,初始化完成了oled后,才可以显示,操作完成flash后,又要调整参数软件上很麻烦

  • 2024-05-15
  • 发表了主题帖: 【NUCLEO-U083RC】EXIT中断测试及功耗测试

    STM32U083RC的带有多种运行模式,其中一种是“待机模式”和“运行模式”, 待机模式:所有的活动暂停,只保留SRAM的内容。 运行模式:正常的运行模式。所有的活动正常进行。 两种模式之间可以自由切换。这样的设计可以在不需要MCU工作时节省电力。本次的进行两种模式切换的测试。 准备工作 开发板的JP5,跳线打开。接入万用表的电流测量档插孔。将挡位调到mA位准备测量。   2、设置程序配置 需要设置,PA5为输出,PC13为按钮exti类型输入。     3、编写测试程序 首先打开程序,在stm32u0xx_it.C中增加按钮的代码。 /**   * @brief   This function handles external line 13 interrupt request.   * @param  None   * @retval None   */ void USER_BUTTON_IRQHANDLER(void) {   /* Manage Flags */   if(LL_EXTI_IsActiveFallingFlag_0_31(USER_BUTTON_EXTI_LINE) != RESET)   {     LL_EXTI_ClearFallingFlag_0_31(USER_BUTTON_EXTI_LINE);       /* Manage code in main.c.*/     UserButton_Callback();   } } 其中的函数UserButton_Callback()在main.c文件中,声明在main.h中。 /******************************************************************************/ /*   USER IRQ HANDLER TREATMENT                                               */ /******************************************************************************/ /**   * @brief  Function to manage BUTTON IRQ Handler   * @param  None   * @retval None   */ void UserButton_Callback(void) {   /* Turn LED off */   LL_GPIO_ResetOutputPin(LED4_GPIO_Port, LED4_Pin);     /* Configure and enter in Standby Mode */   EnterStandbyMode();     /* Here Device is in Standby mode */ } 关键的函数为EnterStandbyMode();模式切换。 模式切换的代码; /**   * @brief  Function to configure and enter in Standby Mode.   * @param  None   * @retval None   */ void EnterStandbyMode(void) {   /* Wait that user release the User push-button */   while(UserButton_GetState() == 0){}     /* Turn-off LED */   /* Note: LED state at this step depends on blinking state at the instant of user button is pressed. */   LL_GPIO_ResetOutputPin(GPIOA, LL_GPIO_PIN_5);     /* Set wakeup pin polarity */   LL_PWR_SetWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2);     LL_PWR_EnablePUPDCfg();   LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_C, LL_PWR_GPIO_BIT_13);     /* Enable wakeup pin */   LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2);     /* Clear wake up Flag */   LL_PWR_ClearFlag_WU2();   /* As default User push-button state is high level, need to clear all wake up Flag again */     /** Request to enter Standby mode     * Following procedure describe in STM32U0xx Reference Manual     * See PWR part, section Low-power modes, Standby mode     */   /* Set Standby mode when CPU enters deepsleep */   LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);     /* Set SLEEPDEEP bit of Cortex System Control Register */   LL_LPM_EnableDeepSleep();     /* This option is used to ensure that store operations are completed */ #if defined ( __CC_ARM)   __force_stores(); #endif   /* Request Wait For Interrupt */   __WFI(); } 其中的进入待机模式的指令是LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);,但是不要着急,在进入前需要将唤醒引脚模式设置成低电平唤醒 LL_PWR_SetWakeUpPinPolarityLow(LL_PWR_WAKEUP_PIN2); 将引脚设置成上升沿触发 LL_PWR_EnableGPIOPullUp(LL_PWR_GPIO_C, LL_PWR_GPIO_BIT_13); 设置按钮引脚为触发引脚 LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN2); 进入待机模式。 唤醒过程是自动完成地。 4、测试过程 正常运行时,运行电压为3.3V,电流为0.398mA,LD4不断闪烁   进入待机模式。   待机后的电流已经降到uA级了,测量电流为0.12uA   这个电流水平已经很低了。  

  • 回复了主题帖: UC3843如何从外部调整它的占空比?

    UC3843的COMP引脚是用来设置输出PWM波的占空比的设置引脚,FB是在COMP设置后的情况下来改变COMP设置的占空比的脉宽的,所以FB通常用来接收输出电压的反馈,从即时切断PWM的输出。 1.COMP引脚(1脚):PWM比较器的反相输入端,通过外部RC网络进行频率补偿。可调整PWM占空比,以实现输出电压和电流的控制。 2.VFB引脚(2脚):PWM比较器的非反相输入端,用于接收反馈电压信号。当反馈电压与内部参考电压(2.5V)之差大于设定值时,PWM输出脉冲宽度增加,反之减小。 3.CURRENT SENSE引脚(3脚):电流检测输入端,通过外部电流采样电阻将电感器的电流转换为电压信号,输入到此引脚。用于控制输出电流。

统计信息

已有1118人来访过

  • 芯积分:4730
  • 好友:10
  • 主题:523
  • 回复:2278

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言