第一版硬件最后版本
This commit is contained in:
parent
1f170ee8bc
commit
986ea7895d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build/
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"idf.adapterTargetName": "esp32s3"
|
||||
}
|
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
set(EXTRA_COMPONENT_DIRS "./components/rotary_encoder")
|
||||
|
||||
project(pile_cm)
|
10
Makefile
Normal file
10
Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := wifi_station
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/common_components
|
||||
EXTRA_COMPONENT_DIRS += $(IDF_PATH)/examples/peripherals/pcnt/rotary_encoder/components
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
118
README.md
118
README.md
@ -1,118 +0,0 @@
|
||||
# Wi-Fi Station Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
This example shows how to use the Wi-Fi Station functionality of the Wi-Fi driver of ESP for connecting to an Access Point.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Configure the project
|
||||
|
||||
Open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
In the `Example Configuration` menu:
|
||||
|
||||
* Set the Wi-Fi configuration.
|
||||
* Set `WiFi SSID`.
|
||||
* Set `WiFi Password`.
|
||||
|
||||
Optional: If you need, change the other options according to your requirements.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run the monitor tool to view the serial output:
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for all the steps to configure and use the ESP-IDF to build projects.
|
||||
|
||||
* [ESP-IDF Getting Started Guide on ESP32](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/index.html)
|
||||
* [ESP-IDF Getting Started Guide on ESP32-S2](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/get-started/index.html)
|
||||
* [ESP-IDF Getting Started Guide on ESP32-C3](https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/get-started/index.html)
|
||||
|
||||
## Example Output
|
||||
Note that the output, in particular the order of the output, may vary depending on the environment.
|
||||
|
||||
Console output if station connects to AP successfully:
|
||||
```
|
||||
I (589) wifi station: ESP_WIFI_MODE_STA
|
||||
I (599) wifi: wifi driver task: 3ffc08b4, prio:23, stack:3584, core=0
|
||||
I (599) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (599) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (629) wifi: wifi firmware version: 2d94f02
|
||||
I (629) wifi: config NVS flash: enabled
|
||||
I (629) wifi: config nano formating: disabled
|
||||
I (629) wifi: Init dynamic tx buffer num: 32
|
||||
I (629) wifi: Init data frame dynamic rx buffer num: 32
|
||||
I (639) wifi: Init management frame dynamic rx buffer num: 32
|
||||
I (639) wifi: Init management short buffer num: 32
|
||||
I (649) wifi: Init static rx buffer size: 1600
|
||||
I (649) wifi: Init static rx buffer num: 10
|
||||
I (659) wifi: Init dynamic rx buffer num: 32
|
||||
I (759) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0
|
||||
I (769) wifi: mode : sta (30:ae:a4:d9:bc:c4)
|
||||
I (769) wifi station: wifi_init_sta finished.
|
||||
I (889) wifi: new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (889) wifi: state: init -> auth (b0)
|
||||
I (899) wifi: state: auth -> assoc (0)
|
||||
I (909) wifi: state: assoc -> run (10)
|
||||
I (939) wifi: connected with #!/bin/test, aid = 1, channel 6, BW20, bssid = ac:9e:17:7e:31:40
|
||||
I (939) wifi: security type: 3, phy: bgn, rssi: -68
|
||||
I (949) wifi: pm start, type: 1
|
||||
|
||||
I (1029) wifi: AP's beacon interval = 102400 us, DTIM period = 3
|
||||
I (2089) esp_netif_handlers: sta ip: 192.168.77.89, mask: 255.255.255.0, gw: 192.168.77.1
|
||||
I (2089) wifi station: got ip:192.168.77.89
|
||||
I (2089) wifi station: connected to ap SSID:myssid password:mypassword
|
||||
```
|
||||
|
||||
Console output if the station failed to connect to AP:
|
||||
```
|
||||
I (589) wifi station: ESP_WIFI_MODE_STA
|
||||
I (599) wifi: wifi driver task: 3ffc08b4, prio:23, stack:3584, core=0
|
||||
I (599) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (599) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
|
||||
I (629) wifi: wifi firmware version: 2d94f02
|
||||
I (629) wifi: config NVS flash: enabled
|
||||
I (629) wifi: config nano formating: disabled
|
||||
I (629) wifi: Init dynamic tx buffer num: 32
|
||||
I (629) wifi: Init data frame dynamic rx buffer num: 32
|
||||
I (639) wifi: Init management frame dynamic rx buffer num: 32
|
||||
I (639) wifi: Init management short buffer num: 32
|
||||
I (649) wifi: Init static rx buffer size: 1600
|
||||
I (649) wifi: Init static rx buffer num: 10
|
||||
I (659) wifi: Init dynamic rx buffer num: 32
|
||||
I (759) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0
|
||||
I (759) wifi: mode : sta (30:ae:a4:d9:bc:c4)
|
||||
I (769) wifi station: wifi_init_sta finished.
|
||||
I (889) wifi: new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (889) wifi: state: init -> auth (b0)
|
||||
I (1889) wifi: state: auth -> init (200)
|
||||
I (1889) wifi: new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (1889) wifi station: retry to connect to the AP
|
||||
I (1899) wifi station: connect to the AP fail
|
||||
I (3949) wifi station: retry to connect to the AP
|
||||
I (3949) wifi station: connect to the AP fail
|
||||
I (4069) wifi: new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (4069) wifi: state: init -> auth (b0)
|
||||
I (5069) wifi: state: auth -> init (200)
|
||||
I (5069) wifi: new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (5069) wifi station: retry to connect to the AP
|
||||
I (5069) wifi station: connect to the AP fail
|
||||
I (7129) wifi station: retry to connect to the AP
|
||||
I (7129) wifi station: connect to the AP fail
|
||||
I (7249) wifi: new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (7249) wifi: state: init -> auth (b0)
|
||||
I (8249) wifi: state: auth -> init (200)
|
||||
I (8249) wifi: new:<6,0>, old:<6,0>, ap:<255,255>, sta:<6,0>, prof:1
|
||||
I (8249) wifi station: retry to connect to the AP
|
||||
I (8249) wifi station: connect to the AP fail
|
||||
I (10299) wifi station: connect to the AP fail
|
||||
I (10299) wifi station: Failed to connect to SSID:myssid, password:mypassword
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
5
components/motor_ctrl_timer/CMakeLists.txt
Normal file
5
components/motor_ctrl_timer/CMakeLists.txt
Normal file
@ -0,0 +1,5 @@
|
||||
set(COMPONENT_SRCS "motor_ctrl_timer.c")
|
||||
|
||||
idf_component_register(SRCS "${COMPONENT_SRCS}"
|
||||
INCLUDE_DIRS .
|
||||
PRIV_REQUIRES "driver")
|
1
components/motor_ctrl_timer/component.mk
Normal file
1
components/motor_ctrl_timer/component.mk
Normal file
@ -0,0 +1 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
141
components/motor_ctrl_timer/motor_ctrl_timer.c
Normal file
141
components/motor_ctrl_timer/motor_ctrl_timer.c
Normal file
@ -0,0 +1,141 @@
|
||||
/* To set the control period for DC motor Timer
|
||||
|
||||
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 "motor_ctrl_timer.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
#define MOTOR_CTRL_TIMER_DIVIDER (16) // Hardware timer clock divider
|
||||
#define MOTOR_CTRL_TIMER_SCALE (TIMER_BASE_CLK / MOTOR_CTRL_TIMER_DIVIDER) // convert counter value to seconds
|
||||
|
||||
#define MOTOR_CONTROL_TIMER_GROUP TIMER_GROUP_0
|
||||
#define MOTOR_CONTROL_TIMER_ID TIMER_0
|
||||
|
||||
static const char *TAG = "motor_ctrl_timer";
|
||||
|
||||
/**
|
||||
* @brief Callback function of timer intterupt
|
||||
*
|
||||
* @param args The parameter transmited to callback function from timer_isr_callback_add. Args here is for timer_info.
|
||||
* @return
|
||||
* - True Do task yield at the end of ISR
|
||||
* - False Not do task yield at the end of ISR
|
||||
*/
|
||||
static bool IRAM_ATTR motor_ctrl_timer_isr_callback(void *args)
|
||||
{
|
||||
BaseType_t high_task_awoken = pdFALSE;
|
||||
motor_ctrl_timer_info_t *info = (motor_ctrl_timer_info_t *) args;
|
||||
info->pulse_info.pulse_cnt = info->pulse_info.get_pulse_callback(info->pulse_info.callback_args);
|
||||
|
||||
/* Now just send the event data back to the main program task */
|
||||
xQueueSendFromISR(info->timer_evt_que, info, &high_task_awoken);
|
||||
|
||||
return high_task_awoken == pdTRUE; // return whether we need to yield at the end of ISR
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize the motor control timer
|
||||
*
|
||||
* @param timer_info the secondary pointer of motor_ctrl_timer_info_t
|
||||
* @param evt_que timer event queue
|
||||
* @param ctrl_period_ms motor control period
|
||||
* @param pulse_info quadrature encoder pulse information
|
||||
* @return
|
||||
* - ESP_OK: Motor control timer initialized successfully
|
||||
* - ESP_FAIL: motor control timer failed to initialize because of other errors
|
||||
*/
|
||||
esp_err_t motor_ctrl_new_timer(motor_ctrl_timer_info_t **timer_info,
|
||||
QueueHandle_t evt_que,
|
||||
unsigned int ctrl_period_ms,
|
||||
pulse_info_t pulse_info)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
/* Select and initialize basic parameters of the timer */
|
||||
timer_config_t config = {
|
||||
.divider = MOTOR_CTRL_TIMER_DIVIDER,
|
||||
.counter_dir = TIMER_COUNT_UP,
|
||||
.counter_en = TIMER_PAUSE,
|
||||
.alarm_en = TIMER_ALARM_EN,
|
||||
.auto_reload = true,
|
||||
}; // default clock source is APB
|
||||
ret = timer_init(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, &config);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "timer init failed\n");
|
||||
|
||||
/* Timer's counter will initially start from value below.
|
||||
Since auto_reload is set, this value will be automatically reload on alarm */
|
||||
timer_set_counter_value(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, 0);
|
||||
|
||||
/* Configure the alarm value and the interrupt on alarm. */
|
||||
timer_set_alarm_value(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, ctrl_period_ms * MOTOR_CTRL_TIMER_SCALE / 1000);
|
||||
timer_enable_intr(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID);
|
||||
|
||||
/* Check the pointers */
|
||||
ESP_GOTO_ON_FALSE(evt_que, ESP_ERR_INVALID_ARG, err, TAG, "timer event queue handler is NULL\n");
|
||||
ESP_GOTO_ON_FALSE(timer_info, ESP_ERR_INVALID_ARG, err, TAG, "timer info structure pointer is NULL\n");
|
||||
/* Alloc and config the infomation structure for this file */
|
||||
*timer_info = calloc(1, sizeof(motor_ctrl_timer_info_t));
|
||||
ESP_GOTO_ON_FALSE(*timer_info, ESP_ERR_NO_MEM, err, TAG, "timer_info calloc failed\n");
|
||||
(*timer_info)->timer_group = MOTOR_CONTROL_TIMER_GROUP;
|
||||
(*timer_info)->timer_idx = MOTOR_CONTROL_TIMER_ID;
|
||||
(*timer_info)->timer_evt_que = evt_que;
|
||||
(*timer_info)->ctrl_period_ms = ctrl_period_ms;
|
||||
(*timer_info)->pulse_info = pulse_info;
|
||||
timer_isr_callback_add(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, motor_ctrl_timer_isr_callback, *timer_info, 0);
|
||||
|
||||
return ret;
|
||||
err:
|
||||
timer_deinit(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set timer alarm period
|
||||
*
|
||||
* @param period Timer alarm period
|
||||
* @return
|
||||
* - void
|
||||
*/
|
||||
void motor_ctrl_timer_set_period(unsigned int period)
|
||||
{
|
||||
timer_set_alarm_value(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, period * MOTOR_CTRL_TIMER_SCALE / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Start the timer
|
||||
*/
|
||||
void motor_ctrl_timer_start(void)
|
||||
{
|
||||
/* start the timer */
|
||||
timer_start(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Pause the timer and clear the counting value
|
||||
*/
|
||||
void motor_ctrl_timer_stop(void)
|
||||
{
|
||||
/* stop the timer */
|
||||
timer_pause(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID);
|
||||
timer_set_counter_value(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the timer
|
||||
*
|
||||
* @param timer_info the secondary pointer of motor_ctrl_timer_info_t, the memory will be freed
|
||||
*/
|
||||
void motor_ctrl_timer_deinit(motor_ctrl_timer_info_t **timer_info)
|
||||
{
|
||||
if (*timer_info != NULL) {
|
||||
timer_deinit(MOTOR_CONTROL_TIMER_GROUP, MOTOR_CONTROL_TIMER_ID);
|
||||
free(*timer_info);
|
||||
*timer_info = NULL;
|
||||
}
|
||||
}
|
78
components/motor_ctrl_timer/motor_ctrl_timer.h
Normal file
78
components/motor_ctrl_timer/motor_ctrl_timer.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* To set the control period for DC motor Timer
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "driver/timer.h"
|
||||
|
||||
typedef struct {
|
||||
int (*get_pulse_callback)(void *);
|
||||
void *callback_args;
|
||||
int pulse_cnt;
|
||||
} pulse_info_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
timer_group_t timer_group; /* Timer Group number */
|
||||
timer_idx_t timer_idx; /* Timer ID */
|
||||
unsigned int ctrl_period_ms; /* Motor control period, unit in ms */
|
||||
QueueHandle_t timer_evt_que; /* The queue of timer events */
|
||||
pulse_info_t pulse_info;
|
||||
} motor_ctrl_timer_info_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the motor control timer
|
||||
*
|
||||
* @param timer_info the secondary pointer of motor_ctrl_timer_info_t
|
||||
* @param evt_que timer event queue
|
||||
* @param ctrl_period_ms motor control period
|
||||
* @param pulse_info quadrature encoder pulse information
|
||||
* @return
|
||||
* - ESP_OK: Motor control timer initialized successfully
|
||||
* - ESP_FAIL: motor control timer failed to initialize because of other errors
|
||||
*/
|
||||
esp_err_t motor_ctrl_new_timer(motor_ctrl_timer_info_t **timer_info,
|
||||
QueueHandle_t evt_que,
|
||||
unsigned int ctrl_period_ms,
|
||||
pulse_info_t pulse_info);
|
||||
|
||||
/**
|
||||
* @brief Set timer alarm period
|
||||
*
|
||||
* @param period Timer alarm period
|
||||
*/
|
||||
void motor_ctrl_timer_set_period(unsigned int period);
|
||||
|
||||
/**
|
||||
* @brief Start the timer
|
||||
*/
|
||||
void motor_ctrl_timer_start(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Pause the timer and clear the counting value
|
||||
*/
|
||||
void motor_ctrl_timer_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the timer
|
||||
*
|
||||
* @param timer_info the secondary pointer of motor_ctrl_timer_info_t, the memory will be freed
|
||||
*/
|
||||
void motor_ctrl_timer_deinit(motor_ctrl_timer_info_t **timer_info);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
7
components/rotary_encoder/CMakeLists.txt
Normal file
7
components/rotary_encoder/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
set(component_srcs "src/rotary_encoder_pcnt_ec11.c")
|
||||
|
||||
idf_component_register(SRCS "${component_srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS ""
|
||||
PRIV_REQUIRES "driver"
|
||||
REQUIRES "")
|
3
components/rotary_encoder/component.mk
Normal file
3
components/rotary_encoder/component.mk
Normal file
@ -0,0 +1,3 @@
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
||||
COMPONENT_SRCDIRS := src
|
127
components/rotary_encoder/include/rotary_encoder.h
Normal file
127
components/rotary_encoder/include/rotary_encoder.h
Normal file
@ -0,0 +1,127 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
/**
|
||||
* @brief Type of Rotary underlying device handle
|
||||
*
|
||||
*/
|
||||
typedef void *rotary_encoder_dev_t;
|
||||
|
||||
/**
|
||||
* @brief Type of rotary encoder configuration
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
rotary_encoder_dev_t dev; /*!< Underlying device handle */
|
||||
int phase_a_gpio_num; /*!< Phase A GPIO number */
|
||||
int phase_b_gpio_num; /*!< Phase B GPIO number */
|
||||
int flags; /*!< Extra flags */
|
||||
} rotary_encoder_config_t;
|
||||
|
||||
/**
|
||||
* @brief Default rotary encoder configuration
|
||||
*
|
||||
*/
|
||||
#define ROTARY_ENCODER_DEFAULT_CONFIG(dev_hdl, gpio_a, gpio_b) \
|
||||
{ \
|
||||
.dev = dev_hdl, \
|
||||
.phase_a_gpio_num = gpio_a, \
|
||||
.phase_b_gpio_num = gpio_b, \
|
||||
.flags = 0, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type of rotary encoder handle
|
||||
*
|
||||
*/
|
||||
typedef struct rotary_encoder_t rotary_encoder_t;
|
||||
|
||||
/**
|
||||
* @brief Rotary encoder interface
|
||||
*
|
||||
*/
|
||||
struct rotary_encoder_t {
|
||||
/**
|
||||
* @brief Filter out glitch from input signals
|
||||
*
|
||||
* @param encoder Rotary encoder handle
|
||||
* @param max_glitch_us Maximum glitch duration, in us
|
||||
* @return
|
||||
* - ESP_OK: Set glitch filter successfully
|
||||
* - ESP_FAIL: Set glitch filter failed because of other error
|
||||
*/
|
||||
esp_err_t (*set_glitch_filter)(rotary_encoder_t *encoder, uint32_t max_glitch_us);
|
||||
|
||||
/**
|
||||
* @brief Start rotary encoder
|
||||
*
|
||||
* @param encoder Rotary encoder handle
|
||||
* @return
|
||||
* - ESP_OK: Start rotary encoder successfully
|
||||
* - ESP_FAIL: Start rotary encoder failed because of other error
|
||||
*/
|
||||
esp_err_t (*start)(rotary_encoder_t *encoder);
|
||||
|
||||
/**
|
||||
* @brief Stop rotary encoder
|
||||
*
|
||||
* @param encoder Rotary encoder handle
|
||||
* @return
|
||||
* - ESP_OK: Stop rotary encoder successfully
|
||||
* - ESP_FAIL: Stop rotary encoder failed because of other error
|
||||
*/
|
||||
esp_err_t (*stop)(rotary_encoder_t *encoder);
|
||||
|
||||
/**
|
||||
* @brief Recycle rotary encoder memory
|
||||
*
|
||||
* @param encoder Rotary encoder handle
|
||||
* @return
|
||||
* - ESP_OK: Recycle rotary encoder memory successfully
|
||||
* - ESP_FAIL: rotary encoder memory failed because of other error
|
||||
*/
|
||||
esp_err_t (*del)(rotary_encoder_t *encoder);
|
||||
|
||||
/**
|
||||
* @brief Get rotary encoder counter value
|
||||
*
|
||||
* @param encoder Rotary encoder handle
|
||||
* @return Current counter value (the sign indicates the direction of rotation)
|
||||
*/
|
||||
int (*get_counter_value)(rotary_encoder_t *encoder);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create rotary encoder instance for EC11
|
||||
*
|
||||
* @param config Rotary encoder configuration
|
||||
* @param ret_encoder Returned rotary encoder handle
|
||||
* @return
|
||||
* - ESP_OK: Create rotary encoder instance successfully
|
||||
* - ESP_ERR_INVALID_ARG: Create rotary encoder instance failed because of some invalid argument
|
||||
* - ESP_ERR_NO_MEM: Create rotary encoder instance failed because there's no enough capable memory
|
||||
* - ESP_FAIL: Create rotary encoder instance failed because of other error
|
||||
*/
|
||||
esp_err_t rotary_encoder_new_ec11(const rotary_encoder_config_t *config, rotary_encoder_t **ret_encoder);
|
||||
esp_err_t ec11_pcnt_clear(pcnt_unit_t);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
238
components/rotary_encoder/src/rotary_encoder_pcnt_ec11.c
Normal file
238
components/rotary_encoder/src/rotary_encoder_pcnt_ec11.c
Normal file
@ -0,0 +1,238 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include "esp_compiler.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "sys/lock.h"
|
||||
#include "hal/pcnt_hal.h"
|
||||
#include "rotary_encoder.h"
|
||||
|
||||
static const char *TAG = "rotary_encoder";
|
||||
|
||||
#define ROTARY_CHECK(a, msg, tag, ret, ...) \
|
||||
do \
|
||||
{ \
|
||||
if (unlikely(!(a))) \
|
||||
{ \
|
||||
ESP_LOGE(TAG, "%s(%d): " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
ret_code = ret; \
|
||||
goto tag; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EC11_PCNT_DEFAULT_HIGH_LIMIT (32767)
|
||||
#define EC11_PCNT_DEFAULT_LOW_LIMIT (-32768)
|
||||
|
||||
// A flag to identify if pcnt isr service has been installed.
|
||||
static bool is_pcnt_isr_service_installed = false;
|
||||
// A lock to avoid pcnt isr service being installed twice in multiple threads.
|
||||
static _lock_t isr_service_install_lock;
|
||||
#define LOCK_ACQUIRE() _lock_acquire(&isr_service_install_lock)
|
||||
#define LOCK_RELEASE() _lock_release(&isr_service_install_lock)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int accumu_count;
|
||||
rotary_encoder_t parent;
|
||||
pcnt_unit_t pcnt_unit;
|
||||
} ec11_t;
|
||||
|
||||
static esp_err_t ec11_set_glitch_filter(rotary_encoder_t *encoder, uint32_t max_glitch_us)
|
||||
{
|
||||
esp_err_t ret_code = ESP_OK;
|
||||
ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
|
||||
|
||||
/* Configure and enable the input filter */
|
||||
ROTARY_CHECK(pcnt_set_filter_value(ec11->pcnt_unit, max_glitch_us * 80) == ESP_OK, "set glitch filter failed", err, ESP_FAIL);
|
||||
|
||||
if (max_glitch_us)
|
||||
{
|
||||
pcnt_filter_enable(ec11->pcnt_unit);
|
||||
}
|
||||
else
|
||||
{
|
||||
pcnt_filter_disable(ec11->pcnt_unit);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
static esp_err_t ec11_start(rotary_encoder_t *encoder)
|
||||
{
|
||||
ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
|
||||
pcnt_counter_resume(ec11->pcnt_unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t ec11_stop(rotary_encoder_t *encoder)
|
||||
{
|
||||
ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
|
||||
pcnt_counter_pause(ec11->pcnt_unit);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static int ec11_get_counter_value(rotary_encoder_t *encoder)
|
||||
{
|
||||
ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
|
||||
int16_t val = 0;
|
||||
pcnt_get_counter_value(ec11->pcnt_unit, &val);
|
||||
return val + ec11->accumu_count;
|
||||
}
|
||||
|
||||
static esp_err_t ec11_del(rotary_encoder_t *encoder)
|
||||
{
|
||||
ec11_t *ec11 = __containerof(encoder, ec11_t, parent);
|
||||
free(ec11);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void ec11_pcnt_overflow_handler(void *arg)
|
||||
{
|
||||
ec11_t *ec11 = (ec11_t *)arg;
|
||||
uint32_t status = 0;
|
||||
pcnt_get_event_status(ec11->pcnt_unit, &status);
|
||||
|
||||
if (status & PCNT_EVT_H_LIM)
|
||||
{
|
||||
ec11->accumu_count += EC11_PCNT_DEFAULT_HIGH_LIMIT;
|
||||
}
|
||||
else if (status & PCNT_EVT_L_LIM)
|
||||
{
|
||||
ec11->accumu_count += EC11_PCNT_DEFAULT_LOW_LIMIT;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t rotary_encoder_new_ec11(const rotary_encoder_config_t *config, rotary_encoder_t **ret_encoder)
|
||||
{
|
||||
esp_err_t ret_code = ESP_OK;
|
||||
ec11_t *ec11 = NULL;
|
||||
|
||||
ROTARY_CHECK(config, "configuration can't be null", err, ESP_ERR_INVALID_ARG);
|
||||
ROTARY_CHECK(ret_encoder, "can't assign context to null", err, ESP_ERR_INVALID_ARG);
|
||||
|
||||
ec11 = calloc(1, sizeof(ec11_t));
|
||||
ROTARY_CHECK(ec11, "allocate context memory failed", err, ESP_ERR_NO_MEM);
|
||||
|
||||
ec11->pcnt_unit = (pcnt_unit_t)(config->dev);
|
||||
|
||||
// Configure channel 0
|
||||
pcnt_config_t dev_config = {
|
||||
.pulse_gpio_num = config->phase_a_gpio_num,
|
||||
.ctrl_gpio_num = config->phase_b_gpio_num,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = ec11->pcnt_unit,
|
||||
.pos_mode = PCNT_COUNT_DEC,
|
||||
.neg_mode = PCNT_COUNT_INC,
|
||||
.lctrl_mode = PCNT_MODE_REVERSE,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = EC11_PCNT_DEFAULT_HIGH_LIMIT,
|
||||
.counter_l_lim = EC11_PCNT_DEFAULT_LOW_LIMIT,
|
||||
};
|
||||
if (config->flags == 1)
|
||||
{
|
||||
dev_config.pulse_gpio_num = config->phase_b_gpio_num;
|
||||
dev_config.ctrl_gpio_num = config->phase_a_gpio_num;
|
||||
}
|
||||
if (config->flags == 2)
|
||||
{
|
||||
dev_config.pos_mode = PCNT_COUNT_DIS;
|
||||
dev_config.neg_mode = PCNT_COUNT_INC;
|
||||
dev_config.lctrl_mode = PCNT_MODE_KEEP;
|
||||
dev_config.hctrl_mode = PCNT_MODE_REVERSE;
|
||||
}
|
||||
else if (config->flags == 3)
|
||||
{
|
||||
dev_config.pos_mode = PCNT_COUNT_DIS;
|
||||
dev_config.neg_mode = PCNT_COUNT_INC;
|
||||
dev_config.lctrl_mode = PCNT_MODE_REVERSE;
|
||||
dev_config.hctrl_mode = PCNT_MODE_KEEP;
|
||||
}
|
||||
ROTARY_CHECK(pcnt_unit_config(&dev_config) == ESP_OK, "config pcnt channel 0 failed", err, ESP_FAIL);
|
||||
|
||||
// Configure channel 1
|
||||
dev_config.pulse_gpio_num = config->phase_b_gpio_num;
|
||||
dev_config.ctrl_gpio_num = config->phase_a_gpio_num;
|
||||
dev_config.channel = PCNT_CHANNEL_1;
|
||||
dev_config.pos_mode = PCNT_COUNT_INC;
|
||||
dev_config.neg_mode = PCNT_COUNT_DEC;
|
||||
if (config->flags == 1)
|
||||
{
|
||||
dev_config.pulse_gpio_num = config->phase_a_gpio_num;
|
||||
dev_config.ctrl_gpio_num = config->phase_b_gpio_num;
|
||||
}
|
||||
else if (config->flags == 2)
|
||||
{
|
||||
dev_config.pulse_gpio_num = config->phase_a_gpio_num,
|
||||
dev_config.ctrl_gpio_num = config->phase_b_gpio_num,
|
||||
dev_config.pos_mode = PCNT_COUNT_DIS;
|
||||
dev_config.neg_mode = PCNT_COUNT_DEC ;
|
||||
dev_config.lctrl_mode = PCNT_MODE_REVERSE;
|
||||
dev_config.hctrl_mode = PCNT_MODE_KEEP;
|
||||
}
|
||||
else if (config->flags == 3)
|
||||
{
|
||||
dev_config.pulse_gpio_num = config->phase_a_gpio_num,
|
||||
dev_config.ctrl_gpio_num = config->phase_b_gpio_num,
|
||||
dev_config.pos_mode = PCNT_COUNT_DIS;
|
||||
dev_config.neg_mode = PCNT_COUNT_DEC ;
|
||||
dev_config.lctrl_mode = PCNT_MODE_KEEP;
|
||||
dev_config.hctrl_mode = PCNT_MODE_REVERSE;
|
||||
}
|
||||
ROTARY_CHECK(pcnt_unit_config(&dev_config) == ESP_OK, "config pcnt channel 1 failed", err, ESP_FAIL);
|
||||
|
||||
// PCNT pause and reset value
|
||||
pcnt_counter_pause(ec11->pcnt_unit);
|
||||
pcnt_counter_clear(ec11->pcnt_unit);
|
||||
|
||||
// register interrupt handler in a thread-safe way
|
||||
LOCK_ACQUIRE();
|
||||
if (!is_pcnt_isr_service_installed)
|
||||
{
|
||||
ROTARY_CHECK(pcnt_isr_service_install(0) == ESP_OK, "install isr service failed", err, ESP_FAIL);
|
||||
// make sure pcnt isr service won't be installed more than one time
|
||||
is_pcnt_isr_service_installed = true;
|
||||
}
|
||||
LOCK_RELEASE();
|
||||
|
||||
pcnt_isr_handler_add(ec11->pcnt_unit, ec11_pcnt_overflow_handler, ec11);
|
||||
|
||||
pcnt_event_enable(ec11->pcnt_unit, PCNT_EVT_H_LIM);
|
||||
pcnt_event_enable(ec11->pcnt_unit, PCNT_EVT_L_LIM);
|
||||
|
||||
ec11->parent.del = ec11_del;
|
||||
ec11->parent.start = ec11_start;
|
||||
ec11->parent.stop = ec11_stop;
|
||||
ec11->parent.set_glitch_filter = ec11_set_glitch_filter;
|
||||
ec11->parent.get_counter_value = ec11_get_counter_value;
|
||||
|
||||
*ret_encoder = &(ec11->parent);
|
||||
return ESP_OK;
|
||||
err:
|
||||
if (ec11)
|
||||
{
|
||||
free(ec11);
|
||||
}
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
|
||||
int ec11_pcnt_clear(pcnt_unit_t unit)
|
||||
{
|
||||
return pcnt_counter_clear(unit);
|
||||
}
|
9
dependencies.lock
Normal file
9
dependencies.lock
Normal file
@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 4.4.4
|
||||
manifest_hash: dcf4d39b94252de130019eadceb989d72b0dbc26b552cfdcbb50f6da531d2b92
|
||||
target: esp32s3
|
||||
version: 1.0.0
|
18
main/CMakeLists.txt
Normal file
18
main/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
"modbus-tcp.c"
|
||||
"can_network.c"
|
||||
"./stm32/ads1220.c"
|
||||
"./stm32/bl0939.c"
|
||||
"./stm32/capture.c"
|
||||
"./stm32/comm.c"
|
||||
"./stm32/depth.c"
|
||||
"./stm32/fram.c"
|
||||
"./stm32/flow.c"
|
||||
"./stm32/utils.c"
|
||||
"./stm32/config.c"
|
||||
"./stm32/ModbusS.c"
|
||||
"./stm32/ModbusM.c"
|
||||
"./stm32/uart0_modbus_slave.c"
|
||||
"wifi_softap.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
45
main/Kconfig.projbuild
Normal file
45
main/Kconfig.projbuild
Normal file
@ -0,0 +1,45 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config ESP_WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config ESP_WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config ESP_MAXIMUM_RETRY
|
||||
int "Maximum retry"
|
||||
default 5
|
||||
help
|
||||
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
|
||||
|
||||
choice ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD
|
||||
prompt "WiFi Scan auth mode threshold"
|
||||
default ESP_WIFI_AUTH_OPEN
|
||||
help
|
||||
The weakest authmode to accept in the scan mode.
|
||||
|
||||
config ESP_WIFI_AUTH_OPEN
|
||||
bool "OPEN"
|
||||
config ESP_WIFI_AUTH_WEP
|
||||
bool "WEP"
|
||||
config ESP_WIFI_AUTH_WPA_PSK
|
||||
bool "WPA PSK"
|
||||
config ESP_WIFI_AUTH_WPA2_PSK
|
||||
bool "WPA2 PSK"
|
||||
config ESP_WIFI_AUTH_WPA_WPA2_PSK
|
||||
bool "WPA/WPA2 PSK"
|
||||
config ESP_WIFI_AUTH_WPA3_PSK
|
||||
bool "WPA3 PSK"
|
||||
config ESP_WIFI_AUTH_WPA2_WPA3_PSK
|
||||
bool "WPA2/WPA3 PSK"
|
||||
config ESP_WIFI_AUTH_WAPI_PSK
|
||||
bool "WAPI PSK"
|
||||
endchoice
|
||||
|
||||
endmenu
|
257
main/can_network.c
Normal file
257
main/can_network.c
Normal file
@ -0,0 +1,257 @@
|
||||
/* TWAI Network Slave 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following example demonstrates a slave node in a TWAI network. The slave
|
||||
* node is responsible for sending data messages to the master. The example will
|
||||
* execute multiple iterations, with each iteration the slave node will do the
|
||||
* following:
|
||||
* 1) Start the TWAI driver
|
||||
* 2) Listen for ping messages from master, and send ping response
|
||||
* 3) Listen for start command from master
|
||||
* 4) Send data messages to master and listen for stop command
|
||||
* 5) Send stop response to master
|
||||
* 6) Stop the TWAI driver
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/twai.h"
|
||||
|
||||
#include "can_network.h"
|
||||
|
||||
/* --------------------- Definitions and static variables ------------------ */
|
||||
// Example Configuration
|
||||
#define DATA_PERIOD_MS 50
|
||||
#define NO_OF_ITERS 3
|
||||
#define ITER_DELAY_MS 1000
|
||||
#define RX_TASK_PRIO 41 // Receiving task priority
|
||||
#define TX_TASK_PRIO 42 // Sending task priority
|
||||
#define CTRL_TSK_PRIO 10 // Control task priority
|
||||
#define TX_GPIO_NUM 14
|
||||
#define RX_GPIO_NUM 21
|
||||
#define TAG "CAN"
|
||||
|
||||
#define ID_MASTER_STOP_CMD 0x0A0
|
||||
#define ID_MASTER_START_CMD 0x0A1
|
||||
#define ID_MASTER_PING 0x0A2
|
||||
#define ID_SLAVE_STOP_RESP 0x0B0
|
||||
#define ID_SLAVE_DATA 0x0B1
|
||||
#define ID_SLAVE_PING_RESP 0x0B2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TX_SEND_PING_RESP,
|
||||
TX_SEND_DATA,
|
||||
TX_SEND_STOP_RESP,
|
||||
TX_TASK_EXIT,
|
||||
} tx_task_action_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RX_RECEIVE_PING,
|
||||
RX_RECEIVE_START_CMD,
|
||||
RX_RECEIVE_STOP_CMD,
|
||||
RX_TASK_EXIT,
|
||||
} rx_task_action_t;
|
||||
|
||||
|
||||
|
||||
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
|
||||
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
|
||||
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(TX_GPIO_NUM, RX_GPIO_NUM, TWAI_MODE_NORMAL);
|
||||
|
||||
// static const twai_message_t ping_resp = {.identifier = ID_SLAVE_PING_RESP, .data_length_code = 0, .data = {0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
// static const twai_message_t stop_resp = {.identifier = ID_SLAVE_STOP_RESP, .data_length_code = 0, .data = {0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
// Data bytes of data message will be initialized in the transmit task
|
||||
// twai_message_t data_message = {.identifier = ID_SLAVE_DATA, .data_length_code = 8, .data = {0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
|
||||
// static QueueHandle_t tx_task_queue;
|
||||
// static QueueHandle_t rx_task_queue;
|
||||
// static SemaphoreHandle_t ctrl_task_sem;
|
||||
// static SemaphoreHandle_t stop_data_sem;
|
||||
// static SemaphoreHandle_t done_sem;
|
||||
|
||||
/* --------------------------- Tasks and Functions -------------------------- */
|
||||
|
||||
static void twai_receive_task(void *arg)
|
||||
{
|
||||
twai_message_t rx_msg;
|
||||
int i;
|
||||
while (1)
|
||||
{
|
||||
char msg_data_str[32];
|
||||
int index = 0;
|
||||
esp_err_t err = twai_receive(&rx_msg, portMAX_DELAY);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
for (i = 0; i < rx_msg.data_length_code; i++)
|
||||
{
|
||||
index += sprintf(&msg_data_str[i], "%02x ", rx_msg.data[i]);
|
||||
}
|
||||
ESP_LOGI(TAG, "recive msg id=%x,len=%d,data=[%s]", rx_msg.identifier, rx_msg.data_length_code, msg_data_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// static void twai_transmit_task(void *arg)
|
||||
// {
|
||||
// while (1)
|
||||
// {
|
||||
// tx_task_action_t action;
|
||||
// xQueueReceive(tx_task_queue, &action, portMAX_DELAY);
|
||||
|
||||
// if (action == TX_SEND_PING_RESP)
|
||||
// {
|
||||
// // Transmit ping response to master
|
||||
// twai_transmit(&ping_resp, portMAX_DELAY);
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Transmitted ping response");
|
||||
// xSemaphoreGive(ctrl_task_sem);
|
||||
// }
|
||||
// else if (action == TX_SEND_DATA)
|
||||
// {
|
||||
// // Transmit data messages until stop command is received
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Start transmitting data");
|
||||
// while (1)
|
||||
// {
|
||||
// // FreeRTOS tick count used to simulate sensor data
|
||||
// uint32_t sensor_data = xTaskGetTickCount();
|
||||
// for (int i = 0; i < 4; i++)
|
||||
// {
|
||||
// data_message.data[i] = (sensor_data >> (i * 8)) & 0xFF;
|
||||
// }
|
||||
// twai_transmit(&data_message, portMAX_DELAY);
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Transmitted data value %d", sensor_data);
|
||||
// vTaskDelay(pdMS_TO_TICKS(DATA_PERIOD_MS));
|
||||
// if (xSemaphoreTake(stop_data_sem, 0) == pdTRUE)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if (action == TX_SEND_STOP_RESP)
|
||||
// {
|
||||
// // Transmit stop response to master
|
||||
// twai_transmit(&stop_resp, portMAX_DELAY);
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Transmitted stop response");
|
||||
// xSemaphoreGive(ctrl_task_sem);
|
||||
// }
|
||||
// else if (action == TX_TASK_EXIT)
|
||||
// {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// vTaskDelete(NULL);
|
||||
// }
|
||||
|
||||
// static void twai_control_task(void *arg)
|
||||
// {
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
// tx_task_action_t tx_action;
|
||||
// rx_task_action_t rx_action;
|
||||
|
||||
// for (int iter = 0; iter < NO_OF_ITERS; iter++)
|
||||
// {
|
||||
// ESP_ERROR_CHECK(twai_start());
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Driver started");
|
||||
|
||||
// // Listen of pings from master
|
||||
// rx_action = RX_RECEIVE_PING;
|
||||
// xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
// // Send ping response
|
||||
// tx_action = TX_SEND_PING_RESP;
|
||||
// xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
// // Listen for start command
|
||||
// rx_action = RX_RECEIVE_START_CMD;
|
||||
// xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
// // Start sending data messages and listen for stop command
|
||||
// tx_action = TX_SEND_DATA;
|
||||
// rx_action = RX_RECEIVE_STOP_CMD;
|
||||
// xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
|
||||
// xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
// // Send stop response
|
||||
// tx_action = TX_SEND_STOP_RESP;
|
||||
// xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
|
||||
// xSemaphoreTake(ctrl_task_sem, portMAX_DELAY);
|
||||
|
||||
// // Wait for bus to become free
|
||||
// twai_status_info_t status_info;
|
||||
// twai_get_status_info(&status_info);
|
||||
// while (status_info.msgs_to_tx > 0)
|
||||
// {
|
||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
||||
// twai_get_status_info(&status_info);
|
||||
// }
|
||||
|
||||
// ESP_ERROR_CHECK(twai_stop());
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Driver stopped");
|
||||
// vTaskDelay(pdMS_TO_TICKS(ITER_DELAY_MS));
|
||||
// }
|
||||
|
||||
// // Stop TX and RX tasks
|
||||
// tx_action = TX_TASK_EXIT;
|
||||
// rx_action = RX_TASK_EXIT;
|
||||
// xQueueSend(tx_task_queue, &tx_action, portMAX_DELAY);
|
||||
// xQueueSend(rx_task_queue, &rx_action, portMAX_DELAY);
|
||||
|
||||
// // Delete Control task
|
||||
// xSemaphoreGive(done_sem);
|
||||
// vTaskDelete(NULL);
|
||||
// }
|
||||
|
||||
|
||||
void can_init(void)
|
||||
{
|
||||
// Add short delay to allow master it to initialize first
|
||||
|
||||
// Create semaphores and tasks
|
||||
// tx_task_queue = xQueueCreate(1, sizeof(tx_task_action_t));
|
||||
// rx_task_queue = xQueueCreate(1, sizeof(rx_task_action_t));
|
||||
// ctrl_task_sem = xSemaphoreCreateBinary();
|
||||
// stop_data_sem = xSemaphoreCreateBinary();;
|
||||
// done_sem = xSemaphoreCreateBinary();;
|
||||
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
ESP_LOGI(TAG, "Driver installed");
|
||||
|
||||
xTaskCreatePinnedToCore(twai_receive_task, "CAN_rx", 1024, NULL, RX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
twai_start();
|
||||
// xTaskCreatePinnedToCore(twai_transmit_task, "TWAI_tx", 4096, NULL, TX_TASK_PRIO, NULL, tskNO_AFFINITY);
|
||||
// xTaskCreatePinnedToCore(twai_control_task, "TWAI_ctrl", 4096, NULL, CTRL_TSK_PRIO, NULL, tskNO_AFFINITY);
|
||||
|
||||
// Install TWAI driver, trigger tasks to start
|
||||
// ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
|
||||
|
||||
// xSemaphoreGive(ctrl_task_sem); // Start Control task
|
||||
// xSemaphoreTake(done_sem, portMAX_DELAY); // Wait for tasks to complete
|
||||
|
||||
// //Uninstall TWAI driver
|
||||
// ESP_ERROR_CHECK(twai_driver_uninstall());
|
||||
// ESP_LOGI(EXAMPLE_TAG, "Driver uninstalled");
|
||||
|
||||
// //Cleanup
|
||||
// vSemaphoreDelete(ctrl_task_sem);
|
||||
// vSemaphoreDelete(stop_data_sem);
|
||||
// vSemaphoreDelete(done_sem);
|
||||
// vQueueDelete(tx_task_queue);
|
||||
// vQueueDelete(rx_task_queue);
|
||||
}
|
19
main/can_network.h
Normal file
19
main/can_network.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __CAN_NETWORK_H
|
||||
#define __CAN_NETWORK_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void can_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HELLOWERLOD_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
|
8
main/component.mk
Normal file
8
main/component.mk
Normal file
@ -0,0 +1,8 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
108
main/main.c
Normal file
108
main/main.c
Normal file
@ -0,0 +1,108 @@
|
||||
/* WiFi station 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 <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <stdio.h>
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include "can_network.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_check.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "driver/mcpwm.h"
|
||||
|
||||
/* The examples use WiFi configuration that you can set via project configuration menu
|
||||
|
||||
If you'd rather not, just change the below entries to strings with
|
||||
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
|
||||
*/
|
||||
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
|
||||
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
|
||||
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
|
||||
|
||||
#if CONFIG_ESP_WIFI_AUTH_OPEN
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WEP
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK
|
||||
#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK
|
||||
#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK
|
||||
#endif
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected*/
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define WIFI_CONNECTED_BIT BIT0
|
||||
#define WIFI_FAIL_BIT BIT1
|
||||
|
||||
static const char *TAG = "main";
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
extern void wifi_init_softap(void);
|
||||
|
||||
void ads1220_init(void);
|
||||
|
||||
extern void can_init(void);
|
||||
extern void FLOW_init();
|
||||
extern void DEPTH_init();
|
||||
extern void BL0939_init(void);
|
||||
extern void ads1220_task_start(void);
|
||||
extern void ModBusTCPSlave_init(void);
|
||||
extern esp_err_t i2c_master_init(void);
|
||||
extern void config_load(void);
|
||||
extern void uart0_modbus_slave_init(void);
|
||||
uint32_t rtc_clk_apb_freq;
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
//Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ESP_ERROR_CHECK(i2c_master_init());
|
||||
config_load();
|
||||
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
|
||||
rtc_clk_apb_freq = rtc_clk_apb_freq_get();
|
||||
ESP_LOGI(TAG, "rtc_clk_apb_freq=%d", rtc_clk_apb_freq);
|
||||
wifi_init_softap();
|
||||
// wifi_init_sta();
|
||||
// can_init();
|
||||
|
||||
ModBusTCPSlave_init();
|
||||
ads1220_task_start(); // test succeed
|
||||
BL0939_init(); // test succeed
|
||||
DEPTH_init();
|
||||
FLOW_init();
|
||||
uart0_modbus_slave_init();
|
||||
}
|
138
main/modbus-tcp.c
Normal file
138
main/modbus-tcp.c
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "stm32/ModbusS.h"
|
||||
// #include "log.h"
|
||||
|
||||
#define LOG_TAG "[mb_tcp_sr]: "
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
/* Private define ------------------------------------------------------------*/
|
||||
/* Private macro -------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
// static err_t ModBusSlave_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
|
||||
// static err_t ModBusSlave_accept(void *arg, struct tcp_pcb *pcb, err_t err);
|
||||
// static void ModBusSlave_conn_err(void *arg, err_t err);
|
||||
// static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *pcb);
|
||||
/* Private functions ---------------------------------------------------------*/
|
||||
/**
|
||||
* @brief Called when a data is received on the telnet connection
|
||||
* @param arg the user argument
|
||||
* @param pcb the tcp_pcb that has received the data
|
||||
* @param p the packet buffer
|
||||
* @param err the error value linked with the received data
|
||||
* @retval error value
|
||||
*/
|
||||
int ModBusTcpMonitor;
|
||||
static err_t ModBusSlave_recv(void *arg, struct tcp_pcb *newpcb, struct pbuf *p, err_t err) {
|
||||
/* We perform here any necessary processing on the pbuf */
|
||||
if (p != NULL) {
|
||||
uint8_t *txbuf;
|
||||
uint8_t *rxbuf;
|
||||
int txlen, rxlen;
|
||||
/* We call this function to tell the LwIp that we have processed the data */
|
||||
/* This lets the stack advertise a larger window, so more data can be received*/
|
||||
tcp_recved(newpcb, p->tot_len);
|
||||
rxbuf = (uint8_t *)p->payload;
|
||||
rxlen = p->len;
|
||||
if (rxlen < 6) {
|
||||
pbuf_free(p);
|
||||
return tcp_close(newpcb);
|
||||
}
|
||||
txbuf = (uint8_t *)mem_malloc(1024 + 16);
|
||||
if (txbuf == NULL) {
|
||||
return tcp_close(newpcb);
|
||||
}
|
||||
ModBusTcpMonitor = 0;
|
||||
txlen = ModbusSlaveProcess(&txbuf[6], &rxbuf[6], (rxlen - 6), 0); //以前有 2023年4月24日14:39:11
|
||||
// log_printf(LINFO, LOG_TAG "[%s] ModbusSlaveProcess (ret=%d)", __FUNCTION__, txlen);
|
||||
if (txlen > 0) {
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
txbuf[i] = rxbuf[i];
|
||||
}
|
||||
txbuf[4] = (uint8_t)(txlen >> 8);
|
||||
txbuf[5] = (uint8_t)(txlen & 0xff);
|
||||
tcp_write(newpcb, txbuf, txlen + 6, 1);
|
||||
ModBusTcpMonitor = 0;
|
||||
}
|
||||
mem_free(txbuf);
|
||||
/* End of processing, we free the pbuf */
|
||||
pbuf_free(p);
|
||||
} else if (err == ERR_OK) {
|
||||
/* When the pbuf is NULL and the err is ERR_OK, the remote end is closing the connection. */
|
||||
/* We free the allocated memory and we close the connection */
|
||||
// log_printf(LWARN, LOG_TAG "remote end is closing the connection\n");
|
||||
tcp_err(newpcb, NULL);
|
||||
tcp_recv(newpcb, NULL);
|
||||
tcp_poll(newpcb, NULL, 120); // 60 second timeout
|
||||
// return tcp_close(newpcb);
|
||||
err_t err_p = tcp_close(newpcb);
|
||||
if (ERR_OK != err_p) {
|
||||
// log_printf(LERROR, LOG_TAG "close error. err:%d\n", err_p);
|
||||
}
|
||||
return err_p;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
/**
|
||||
* @brief This function is called when an error occurs on the connection
|
||||
* @param arg
|
||||
* @parm err
|
||||
* @retval None
|
||||
*/
|
||||
static void ModBusSlave_conn_err(void *arg, err_t err) {
|
||||
// log_printf(LERROR, LOG_TAG "connection error, err:%d\n", err);
|
||||
}
|
||||
static err_t ModBusSlave_poll(void *arg, struct tcp_pcb *newpcb) {
|
||||
if (newpcb) {
|
||||
// log_printf(LERROR, LOG_TAG "close pcb\n");
|
||||
tcp_close(newpcb);
|
||||
newpcb = NULL;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
/**
|
||||
* @brief This function when the Telnet connection is established
|
||||
* @param arg user supplied argument
|
||||
* @param pcb the tcp_pcb which accepted the connection
|
||||
* @param err error value
|
||||
* @retval ERR_OK
|
||||
*/
|
||||
static err_t ModBusSlave_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
|
||||
/* Tell LwIP to associate this structure with this connection. */
|
||||
// tcp_arg(pcb, mem_calloc(sizeof(struct name), 1));
|
||||
/* Configure LwIP to use our call back functions. */
|
||||
tcp_err(pcb, ModBusSlave_conn_err);
|
||||
tcp_recv(pcb, ModBusSlave_recv);
|
||||
tcp_poll(pcb, ModBusSlave_poll, 120); // 60 second timeout
|
||||
/* Send out the first message */
|
||||
// tcp_write(pcb, GREETING, strlen(GREETING), 1);
|
||||
return ERR_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Initialize the hello application
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void ModBusTCPSlave_init(void) {
|
||||
struct tcp_pcb *pcb;
|
||||
/* Create a new TCP control block */
|
||||
pcb = tcp_new();
|
||||
/* Assign to the new pcb a local IP address and a port number */
|
||||
/* Using IP_ADDR_ANY allow the pcb to be used by any local interface */
|
||||
tcp_bind(pcb, IP_ADDR_ANY, 502);
|
||||
/* Set the connection to the LISTEN state */
|
||||
pcb = tcp_listen(pcb);
|
||||
/* Specify the function to be called when a connection is established */
|
||||
tcp_accept(pcb, ModBusSlave_accept);
|
||||
// LSAPI_Log_Debug("ModBus Tcp server listen port:%d\n", 502);
|
||||
}
|
||||
/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
|
27
main/modbus-tcp.h
Normal file
27
main/modbus-tcp.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __HELLOWERLOD_H
|
||||
#define __HELLOWERLOD_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
/** @defgroup helloworld_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
void HelloWorld_init(void);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HELLOWERLOD_H */
|
||||
|
||||
/******************* (C) COPYRIGHT 2009 STMicroelectronics *****END OF FILE****/
|
680
main/stm32/ModbusM.c
Normal file
680
main/stm32/ModbusM.c
Normal file
@ -0,0 +1,680 @@
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "ModbusM.h"
|
||||
#include "ModbusS.h"
|
||||
#include "config.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "uart.h"
|
||||
#include "driver/uart.h"
|
||||
|
||||
#define ZB_CHANNEL 1
|
||||
|
||||
extern uint16_t gWordVar[];
|
||||
//uint16_t g_tmp[100];
|
||||
device_t zb_device[ZB_CHANNEL];
|
||||
|
||||
send_t zb_send[16];
|
||||
|
||||
#define GetTicks xTaskGetTickCount
|
||||
#define UART1_TXBUF_SIZE 256
|
||||
|
||||
int zbapi_send_write(device_t *device, send_t *sender);
|
||||
int zbapi_send_req(device_t *device);
|
||||
int max(int x, int y)
|
||||
{
|
||||
if (x > y)
|
||||
return x;
|
||||
else
|
||||
return y;
|
||||
}
|
||||
|
||||
//static float pow_user(float x, float y)
|
||||
//{
|
||||
// int i;
|
||||
// float tmp = 1;
|
||||
// for (i = 0; i < y; i++)
|
||||
// {
|
||||
// tmp = tmp * x;
|
||||
// }
|
||||
// return tmp;
|
||||
//}
|
||||
uint16_t bin2bcd(uint16_t bin)
|
||||
{
|
||||
uint16_t bcd;
|
||||
uint8_t buf[4];
|
||||
if (bin > 9999)
|
||||
{
|
||||
bin = 9999;
|
||||
}
|
||||
buf[0] = bin % 10;
|
||||
bin /= 10;
|
||||
buf[1] = bin % 10;
|
||||
bin /= 10;
|
||||
buf[2] = bin % 10;
|
||||
buf[3] = bin / 10;
|
||||
bcd = buf[0] | (buf[1] << 4) | (buf[2] << 8) | (buf[3] << 12);
|
||||
return bcd;
|
||||
}
|
||||
int min(int x, int y)
|
||||
{
|
||||
if (x < y)
|
||||
return x;
|
||||
else
|
||||
return y;
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>sn ֵ
|
||||
uint8_t get_new_sn(int device_id)
|
||||
{
|
||||
int i;
|
||||
int sn = 0;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (zb_send[i].device_id == device_id)
|
||||
{
|
||||
sn = max(zb_send[i].sn, sn);
|
||||
}
|
||||
}
|
||||
return sn + 1;
|
||||
}
|
||||
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>豸<EFBFBD><E8B1B8>Сsn<73><6E>Ӧ<EFBFBD><D3A6><EFBFBD>±<EFBFBD>
|
||||
int device_get_send(int device_id)
|
||||
{
|
||||
int i;
|
||||
int sn = 255;
|
||||
int min_index = -1;
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (zb_send[i].device_id == device_id)
|
||||
{
|
||||
if (zb_send[i].sn < sn)
|
||||
{
|
||||
sn = zb_send[i].sn;
|
||||
min_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return min_index;
|
||||
}
|
||||
void on_in_pack_error(device_t *device)
|
||||
{
|
||||
if (device->in_err_cnt[device->in_index] < device->in->max_err_cnt)
|
||||
{
|
||||
if (++device->in_err_cnt[device->in_index] >= device->in->max_err_cnt)
|
||||
{
|
||||
const packet_t *in_pack = device->in->packets + device->in_index;
|
||||
int i;
|
||||
for (i = 0; i < in_pack->length; i++)
|
||||
{
|
||||
uint32_t reg_addr = in_pack->local_addr + i;
|
||||
if (reg_addr < gWORD_SIZE)
|
||||
{
|
||||
gWordVar[reg_addr] = 0;
|
||||
}
|
||||
}
|
||||
if (device->protocol == 255)
|
||||
{
|
||||
if (in_pack->slave > 0 && in_pack->slave <= 10)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
gWordVar[in_pack->local_addr] = 0;
|
||||
}
|
||||
}
|
||||
if (in_pack->slave == 0)
|
||||
{
|
||||
gWordVar[64 + 10] = 0;
|
||||
}
|
||||
}
|
||||
// on_data_error(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
extern int page;
|
||||
void modbus_master_poll(int n)
|
||||
{
|
||||
uint32_t now = GetTicks();
|
||||
// printf("status == %d\n",zb_device[n].status);
|
||||
if (zb_device[n].status == 0) // 空闲状态
|
||||
{
|
||||
if (zb_device[n].out_pending > 0) ////如果有发送请求先处理发送
|
||||
{
|
||||
// printf("out_pending > 0\n");
|
||||
int send_index = device_get_send(n);
|
||||
if (send_index >= 0)
|
||||
{
|
||||
if (now >= zb_send[send_index].next_try_time)
|
||||
{
|
||||
zb_device[n].out_index = send_index;
|
||||
zb_device[n].send_req_time = now;
|
||||
zbapi_send_write(&zb_device[n], &zb_send[send_index]);
|
||||
zb_device[n].status = 0x10;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
zb_device[n].out_pending = 0;
|
||||
}
|
||||
}
|
||||
if (now >= zb_device[n].next_scan_time)
|
||||
{
|
||||
// printf("now >= zb_device[%d]\n",n);
|
||||
zb_device[n].send_req_time = now;
|
||||
zbapi_send_req(&zb_device[n]);
|
||||
zb_device[n].status = 2;
|
||||
}
|
||||
}
|
||||
else if (zb_device[n].status == 1 || zb_device[n].status == 2) //
|
||||
{
|
||||
|
||||
if ((now - zb_device[n].send_req_time) > zb_device[n].in->time_out * 100)
|
||||
{
|
||||
zb_device[n].status = 0; //<2F><>ʱ
|
||||
zb_device[n].ErrCode = 0x01;
|
||||
zb_device[n].ErrCount++;
|
||||
on_in_pack_error(&zb_device[n]);
|
||||
if ((++zb_device[n].try_times >= zb_device[n].in->max_try_times) ||
|
||||
(zb_device[n].in_err_cnt[zb_device[n].in_index] >= zb_device[n].in->max_err_cnt))
|
||||
{
|
||||
if (++zb_device[n].in_index >= zb_device[n].in->packet_cnt)
|
||||
{
|
||||
zb_device[n].in_index = 0;
|
||||
zb_device[n].group_start_time = now;
|
||||
}
|
||||
//zb_device[n].next_scan_time = zb_device[n].group_start_time + zb_device[n].in->scan_rate*10;
|
||||
zb_device[n].try_times = 0;
|
||||
}
|
||||
zb_device[n].next_scan_time = zb_device[n].group_start_time + zb_device[n].in->scan_rate * 10;
|
||||
zb_device[n].status = 0;
|
||||
}
|
||||
}
|
||||
else if (zb_device[n].status == 3) // <20><><EFBFBD>յ<EFBFBD><D5B5>ظ<EFBFBD>
|
||||
{
|
||||
if (++zb_device[n].in_index >= zb_device[n].in->packet_cnt)
|
||||
{
|
||||
zb_device[n].in_index = 0;
|
||||
zb_device[n].group_start_time = now; //+ zb_device[n].in->scan_rate*10;
|
||||
}
|
||||
zb_device[n].next_scan_time = zb_device[n].group_start_time + zb_device[n].in->scan_rate * 10;
|
||||
zb_device[n].status = 255;
|
||||
zb_device[n].try_times = 0;
|
||||
}
|
||||
else if (zb_device[n].status == 0x10) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѷ<EFBFBD><D1B7><EFBFBD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>߳<EFBFBD>ʱ
|
||||
{
|
||||
int index = zb_device[n].out_index;
|
||||
if ((now - zb_device[n].send_req_time) > zb_device[n].in->time_out * 100)
|
||||
{
|
||||
zb_device[n].status = 0; //<2F><>ʱ
|
||||
zb_device[n].ErrCode = 0x01;
|
||||
zb_device[n].ErrCount++;
|
||||
if (++zb_send[index].try_times >= zb_device[n].out->max_try_times) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>
|
||||
{
|
||||
zb_send[index].device_id = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
zb_send[index].next_try_time = now + zb_device[n].out->try_space * 100;
|
||||
}
|
||||
zb_device[n].status = 0;
|
||||
zb_device[n].try_times = 0;
|
||||
}
|
||||
}
|
||||
else if (zb_device[n].status == 0x11) // <20><><EFBFBD>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7>
|
||||
{
|
||||
zb_send[zb_device[n].out_index].device_id = 0xff;
|
||||
zb_device[n].status = 255;
|
||||
zb_device[n].try_times = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((now - zb_device[n].revice_resp_time) >= (zb_device[n].in->scan_space))
|
||||
{
|
||||
zb_device[n].status = 0;
|
||||
zb_device[n].try_times = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// <20><><EFBFBD><EFBFBD><EFBFBD>ཻ
|
||||
int intersection(int x0, int x1, int y0, int y1, int *s, int *e)
|
||||
{
|
||||
int ret = 0;
|
||||
if ((y0 >= x0) && (y0 < x1))
|
||||
{
|
||||
*s = y0;
|
||||
*e = min(x1, y1);
|
||||
ret = 1;
|
||||
}
|
||||
else if ((y1 > x0) && (y1 <= x1))
|
||||
{
|
||||
*s = y1 - 1;
|
||||
*e = min(x1, y1);
|
||||
ret = 1;
|
||||
}
|
||||
else if ((x0 >= y0) && (x0 < y1))
|
||||
{
|
||||
*s = x0;
|
||||
*e = min(y1, x1);
|
||||
ret = 1;
|
||||
}
|
||||
else if ((x1 > y0) && (x1 <= y1))
|
||||
{
|
||||
*s = x1 - 1;
|
||||
*e = min(y1, x1);
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int zb_ModBusWordWriteHook(uint16_t addr, uint16_t length)
|
||||
{
|
||||
int i, j;
|
||||
int ret = 0;
|
||||
for (i = 0; i < ZB_CHANNEL; i++)
|
||||
{
|
||||
if (zb_device[i].out == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < zb_device[i].out->packet_cnt; j++)
|
||||
{
|
||||
int s1, e1;
|
||||
int s2, e2;
|
||||
int s, e;
|
||||
int n;
|
||||
s1 = zb_device[i].out->packets[j].local_addr;
|
||||
e1 = zb_device[i].out->packets[j].local_addr + zb_device[i].out->packets[j].length;
|
||||
s2 = addr;
|
||||
e2 = addr + length;
|
||||
if (intersection(s1, e1, s2, e2, &s, &e))
|
||||
//if((s2 >= s1 && s2 < e1) || (e2 >= s1 && s2 < e1))
|
||||
{
|
||||
for (n = 0; n < 16; n++)
|
||||
{
|
||||
if (zb_send[n].device_id == 0xff)
|
||||
{
|
||||
zb_send[n].sn = get_new_sn(i);
|
||||
zb_send[n].device_id = i;
|
||||
zb_send[n].packet_index = j;
|
||||
zb_send[n].address = s;
|
||||
zb_send[n].length = e - s;
|
||||
zb_send[n].next_try_time = 0;
|
||||
zb_send[n].try_times = 0;
|
||||
zb_device[i].out_pending++;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//extern uint8_t Uart3TxBuf[];
|
||||
//#define txbuf Uart3TxBuf
|
||||
|
||||
int zbapi_send_req(device_t *device)
|
||||
{
|
||||
if (device->protocol == 255)
|
||||
{
|
||||
device->txbuf[0] = device->in->packets[device->in_index].slave;
|
||||
device->txbuf[1] = 0x5a;
|
||||
device->txbuf[2] = 0xaa;
|
||||
device->write(device->txbuf, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t crc;
|
||||
device->txbuf[0] = device->in->packets[device->in_index].slave;
|
||||
device->txbuf[1] = device->in->packets[device->in_index].funcode;
|
||||
device->txbuf[2] = device->in->packets[device->in_index].address >> 8;
|
||||
device->txbuf[3] = device->in->packets[device->in_index].address & 0xff;
|
||||
device->txbuf[4] = device->in->packets[device->in_index].length >> 8;
|
||||
device->txbuf[5] = device->in->packets[device->in_index].length & 0xff;
|
||||
crc = crc16(device->txbuf, 6);
|
||||
device->txbuf[6] = crc >> 8;
|
||||
device->txbuf[7] = crc & 0xff;
|
||||
device->write(device->txbuf, 8);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int zbapi_send_write(device_t *device, send_t *sender)
|
||||
{
|
||||
{
|
||||
int n = 0;
|
||||
uint16_t crc;
|
||||
const packet_t *out_pack = &device->out->packets[sender->packet_index];
|
||||
if (sender->length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
device->txbuf[0] = device->out->packets[sender->packet_index].slave;
|
||||
if (sender->length > 1)
|
||||
{
|
||||
int addr = out_pack->address + (sender->address - out_pack->local_addr);
|
||||
int i;
|
||||
int len;
|
||||
device->txbuf[1] = 0x10;
|
||||
device->txbuf[2] = addr >> 8;
|
||||
device->txbuf[3] = addr & 0xff;
|
||||
device->txbuf[4] = sender->length >> 8;
|
||||
device->txbuf[5] = sender->length & 0xff;
|
||||
device->txbuf[6] = (sender->length * 2) & 0xff;
|
||||
len = 7;
|
||||
for (i = 0; i < sender->length; i++)
|
||||
{
|
||||
uint16_t reg16 = gWordVar[sender->address + i];
|
||||
if (out_pack->device_type == 5)
|
||||
{
|
||||
reg16 = bin2bcd(reg16);
|
||||
}
|
||||
device->txbuf[len++] = reg16 >> 8;
|
||||
device->txbuf[len++] = reg16 & 0xff;
|
||||
}
|
||||
crc = crc16(device->txbuf, len);
|
||||
device->txbuf[len++] = crc >> 8;
|
||||
device->txbuf[len++] = crc & 0xff;
|
||||
n += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int addr = out_pack->address + (sender->address - out_pack->local_addr);
|
||||
uint16_t reg16 = gWordVar[sender->address];
|
||||
device->txbuf[1] = 0x06;
|
||||
device->txbuf[2] = addr >> 8;
|
||||
device->txbuf[3] = addr & 0xff;
|
||||
if (out_pack->device_type == 5)
|
||||
{
|
||||
reg16 = bin2bcd(reg16);
|
||||
}
|
||||
if ((device->protocol == 5) || (device->protocol == 6))
|
||||
{
|
||||
reg16 *= 10;
|
||||
}
|
||||
device->txbuf[4] = reg16 >> 8;
|
||||
device->txbuf[5] = reg16 & 0xff;
|
||||
crc = crc16(device->txbuf, 6);
|
||||
device->txbuf[6] = crc >> 8;
|
||||
device->txbuf[7] = crc & 0xff;
|
||||
n += 8;
|
||||
}
|
||||
if (device->write != NULL)
|
||||
{
|
||||
device->write(device->txbuf, n);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern uint16_t Is_SetFromScreen;
|
||||
|
||||
int modbus_master_on_revice(int ch, uint8_t *rxbuf, int length)
|
||||
{
|
||||
int i;
|
||||
// uint8_t src_addr[8];
|
||||
if (length < 4)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
i = ch;
|
||||
//for(i=0; i<ZB_CHANNEL; i++)//1
|
||||
{
|
||||
if (zb_device[i].status == 2)
|
||||
{
|
||||
zb_device[i].revice_resp_time = GetTicks();
|
||||
{
|
||||
int index = zb_device[i].in_index;
|
||||
if ((zb_device[i].in->packets[index].slave == rxbuf[0]) &&
|
||||
zb_device[i].in->packets[index].funcode == rxbuf[1])
|
||||
{
|
||||
uint16_t crcChk = crc16(rxbuf, length - 2);
|
||||
uint16_t crcData = (rxbuf[length - 2] << 8) | rxbuf[length - 1];
|
||||
if (crcData != crcChk)
|
||||
{
|
||||
zb_device[i].ErrCode = 2; //CRC error
|
||||
zb_device[i].ErrCount++;
|
||||
}
|
||||
else if (rxbuf[0] != zb_device[i].in->packets[index].slave)
|
||||
{
|
||||
zb_device[i].ErrCode = 3; //ADD error
|
||||
zb_device[i].ErrCount++;
|
||||
}
|
||||
else if (rxbuf[1] != zb_device[i].in->packets[index].funcode)
|
||||
{
|
||||
zb_device[i].ErrCode = 4; //Fun err;
|
||||
zb_device[i].ErrCount++;
|
||||
}
|
||||
else if (rxbuf[2] != (zb_device[i].in->packets[index].length * 2))
|
||||
{
|
||||
zb_device[i].ErrCode = 1; //byte miss
|
||||
zb_device[i].ErrCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = 0;
|
||||
// uint32_t reg32;
|
||||
uint16_t addr = zb_device[i].in->packets[index].local_addr;
|
||||
uint8_t len = rxbuf[2] / 2;
|
||||
if (addr >= gWORD_SIZE)
|
||||
{
|
||||
zb_device[i].ErrCode = 5; //regaddr err;
|
||||
goto done;
|
||||
}
|
||||
zb_device[i].ErrCode = 0;
|
||||
switch (zb_device[i].in->packets[index].device_type)
|
||||
{
|
||||
default:
|
||||
|
||||
for (n = 0; n < len; n++)
|
||||
{
|
||||
if (addr + n < gWORD_SIZE)
|
||||
{
|
||||
gWordVar[addr + n] = (rxbuf[3 + n * 2] << 8) | (rxbuf[3 + n * 2 + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
zb_device[i].in_err_cnt[zb_device[i].in_index] = 0;
|
||||
}
|
||||
done:
|
||||
zb_device[i].status = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (zb_device[i].status == 0x10)
|
||||
{
|
||||
zb_device[i].revice_resp_time = GetTicks();
|
||||
//if(memcmp(src_addr,((zb_dev_t*)zb_device[i].ext)->zb_addr,8) == 0)
|
||||
{
|
||||
zb_device[i].status = 0x11;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int meter_count = 4;
|
||||
|
||||
//#define meter_count meter_cfg.count
|
||||
//const int reg_offset[] = {0, 2, 3, 4, 1};
|
||||
|
||||
//static char input_buf[1][414];
|
||||
//static char output_buf[1][212];
|
||||
static char in_err_cnt_buf[1][25];
|
||||
struct input{
|
||||
input_t input;
|
||||
packet_t packet[5];
|
||||
};
|
||||
struct output{
|
||||
output_t output;
|
||||
packet_t packet[5];
|
||||
};
|
||||
struct input input1;
|
||||
struct output output1;
|
||||
|
||||
extern int uart1_tx_start(uint8_t *data, int length);
|
||||
extern uint8_t uart1_txbuf[];
|
||||
//static uint8_t uart_txbuf[ 256 ];
|
||||
//static uint8_t uart_rxbuf[ 256 ];
|
||||
|
||||
static int uart_send(uint8_t *buf, int len)
|
||||
{
|
||||
// uart1_tx_start(buf, len);
|
||||
uart_write_bytes(RS485_UART_PORT_NUM, buf, len);
|
||||
//HAL_UART_Transmit_DMA(&huart1,buf,len);
|
||||
return len;
|
||||
}
|
||||
int ModbusM_init(void)
|
||||
{
|
||||
int i = 0;
|
||||
// int meter_count[4] = {0, 0, 0, 0};
|
||||
// int size;
|
||||
// char *p;
|
||||
// int n;
|
||||
// uint8_t *in_err_cnt;
|
||||
|
||||
zb_device[0].txbuf = uart1_txbuf;
|
||||
zb_device[0].txbuf_size = UART1_TXBUF_SIZE;
|
||||
zb_device[0].write = uart_send;
|
||||
|
||||
{
|
||||
input_t *input;
|
||||
output_t *output;
|
||||
uint8_t *in_err_cnt;
|
||||
|
||||
|
||||
// memset(input_buf[i], 0, sizeof(input_buf[i]));
|
||||
// memset(output_buf[i], 0, sizeof(output_buf[i]));
|
||||
// memset(in_err_cnt_buf[i], 0, sizeof(in_err_cnt_buf[i]));
|
||||
|
||||
output = &output1.output;
|
||||
input = &input1.input;
|
||||
in_err_cnt = (uint8_t *)in_err_cnt_buf[i];
|
||||
|
||||
zb_device[i].in_err_cnt = in_err_cnt;
|
||||
|
||||
input->scan_rate = 10; //*10ms
|
||||
input->time_out = 10; //*100ms
|
||||
input->max_try_times = 2;
|
||||
input->scan_space = 50; //*10ms
|
||||
input->max_err_cnt = 30;
|
||||
|
||||
output->max_try_times = 3;
|
||||
output->try_space = 40;
|
||||
|
||||
zb_device[i].channl = i;
|
||||
zb_device[i].next_scan_time = 0;
|
||||
zb_device[i].status = 0;
|
||||
zb_device[i].try_times = 0;
|
||||
zb_device[i].in_index = 0;
|
||||
zb_device[i].out_pending = 0;
|
||||
zb_device[i].in_err_cnt = in_err_cnt;
|
||||
zb_device[i].in = input;
|
||||
zb_device[i].out = output;
|
||||
// zb_device[i].ext = &serial_port_cfg[i];
|
||||
}
|
||||
{
|
||||
device_t *dev = (device_t *)&zb_device;
|
||||
dev->in->packets[dev->in->packet_cnt].slave = 1;
|
||||
dev->in->packets[dev->in->packet_cnt].funcode = 3;
|
||||
dev->in->packets[dev->in->packet_cnt].address = 0;
|
||||
dev->in->packets[dev->in->packet_cnt].length = 3;
|
||||
dev->in->packets[dev->in->packet_cnt].device_type = 0;
|
||||
dev->in->packets[dev->in->packet_cnt].local_addr = TILT_SENSER_ADDR;
|
||||
dev->in->packets[dev->in->packet_cnt].ch = 0;
|
||||
dev->in->packet_cnt++;
|
||||
|
||||
dev->out->packets[dev->out->packet_cnt].slave = 1;
|
||||
dev->out->packets[dev->out->packet_cnt].funcode = 6;
|
||||
dev->out->packets[dev->out->packet_cnt].local_addr = 10;
|
||||
dev->out->packets[dev->out->packet_cnt].length = 1;
|
||||
dev->out->packets[dev->out->packet_cnt].address = 5;
|
||||
dev->out->packets[dev->out->packet_cnt].device_type = 0;
|
||||
dev->in->packets[dev->in->packet_cnt].ch = 0;
|
||||
dev->out->packet_cnt++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
extern int meter_type;
|
||||
|
||||
void ModbusM_reinit(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 64; i < 64 + 128; i++)
|
||||
{
|
||||
gWordVar[i] = 0;
|
||||
}
|
||||
ModbusM_init();
|
||||
}
|
||||
|
||||
int fill_data(uint8_t *pData, uint16_t local_addr, uint8_t remote_offset, uint8_t length)
|
||||
{
|
||||
uint16_t *pWordVar;
|
||||
int i;
|
||||
*pData++ = remote_offset;
|
||||
*pData++ = length;
|
||||
pWordVar = &gWordVar[local_addr];
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
*pData++ = *pWordVar >> 8;
|
||||
*pData++ = *pWordVar & 0xff;
|
||||
pWordVar++;
|
||||
}
|
||||
return i * 2 + 2;
|
||||
}
|
||||
int build_data(int dest_addr, const int *src_addr_map, int length)
|
||||
{
|
||||
int i;
|
||||
int change_cnt = 0;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
int src_addr = src_addr_map[i];
|
||||
if (dest_addr < gWORD_SIZE && src_addr >= 0 && src_addr < gWORD_SIZE)
|
||||
{
|
||||
if (gWordVar[dest_addr] != gWordVar[src_addr])
|
||||
{
|
||||
gWordVar[dest_addr] = gWordVar[src_addr];
|
||||
change_cnt++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
dest_addr++;
|
||||
}
|
||||
return change_cnt;
|
||||
}
|
||||
int copy_data(int dest_addr, int src_addr, int length)
|
||||
{
|
||||
int i;
|
||||
int change_cnt = 0;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
//int src_addr = src_addr_map[i];
|
||||
if (dest_addr < gWORD_SIZE && src_addr >= 0 && src_addr < gWORD_SIZE)
|
||||
{
|
||||
if (gWordVar[dest_addr] != gWordVar[src_addr])
|
||||
{
|
||||
gWordVar[dest_addr] = gWordVar[src_addr];
|
||||
change_cnt++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
dest_addr++;
|
||||
src_addr++;
|
||||
}
|
||||
return change_cnt;
|
||||
}
|
120
main/stm32/ModbusM.h
Normal file
120
main/stm32/ModbusM.h
Normal file
@ -0,0 +1,120 @@
|
||||
#ifndef _MODBUSM_H_
|
||||
#define _MODBUSM_H_
|
||||
#define uint8 unsigned char
|
||||
#define uint16 unsigned short
|
||||
#define uint32 unsigned int
|
||||
|
||||
typedef struct _MODBUS_MASTRT_
|
||||
{
|
||||
uint8 Status;
|
||||
uint8 ErrCode;
|
||||
|
||||
uint8 Slave;
|
||||
uint8 Function;
|
||||
|
||||
uint8 PackId;
|
||||
uint8 Length;
|
||||
uint16 Address;
|
||||
|
||||
uint16 *Data;
|
||||
|
||||
uint32 txtime;
|
||||
uint32 rxtime;
|
||||
uint16 TxCont;
|
||||
uint16 TimeOut;
|
||||
uint16 CrcErr;
|
||||
uint16 ByteMiss;
|
||||
uint16 OtherErr;
|
||||
}MODBUS_MASTERT_T;
|
||||
typedef struct _MODBUS_READ_T_
|
||||
{
|
||||
uint8 SaveAdd;
|
||||
uint8 Length;
|
||||
uint16 RegAdd;
|
||||
uint16 *pDat;
|
||||
}MODBUS_READ_T;
|
||||
|
||||
|
||||
|
||||
typedef struct _packet_
|
||||
{
|
||||
uint8_t device_type;
|
||||
uint8_t slave;
|
||||
uint8_t funcode;
|
||||
uint8_t ch;
|
||||
uint16_t length;
|
||||
uint16_t address;
|
||||
uint16_t local_addr;
|
||||
uint16_t ext_flg;
|
||||
const void* ext;
|
||||
}packet_t;
|
||||
|
||||
typedef struct _input_
|
||||
{
|
||||
uint8_t packet_cnt;
|
||||
uint8_t max_try_times;
|
||||
uint8_t time_out;
|
||||
|
||||
uint16_t scan_rate;
|
||||
uint16_t scan_space;
|
||||
|
||||
uint8_t max_err_cnt;
|
||||
uint8_t ch;
|
||||
uint8_t rsv[2];
|
||||
packet_t packets[1];
|
||||
}input_t;
|
||||
|
||||
typedef struct _output_
|
||||
{
|
||||
uint8_t packet_cnt;
|
||||
uint8_t max_try_times;
|
||||
uint8_t try_space;
|
||||
uint8_t rsv;
|
||||
packet_t packets[1];
|
||||
}output_t;
|
||||
|
||||
typedef struct _device_
|
||||
{
|
||||
uint8_t channl;
|
||||
uint8_t protocol;
|
||||
uint8_t status;
|
||||
uint8_t in_index;
|
||||
|
||||
uint8_t try_times;
|
||||
uint8_t out_pending;
|
||||
uint8_t out_index;
|
||||
uint8_t ErrCode;
|
||||
|
||||
uint8_t continue_err;
|
||||
uint8_t max_coutinue;
|
||||
uint16_t ErrCount;
|
||||
uint16_t PackId;
|
||||
|
||||
uint32_t group_start_time;
|
||||
uint32_t next_scan_time;
|
||||
uint32_t send_req_time;
|
||||
uint32_t revice_resp_time;
|
||||
uint8_t *txbuf;
|
||||
int txbuf_size;
|
||||
int (*write)(uint8*, int);
|
||||
uint8_t *in_err_cnt;
|
||||
input_t *in;
|
||||
output_t *out;
|
||||
void *ext;
|
||||
}device_t;
|
||||
|
||||
typedef struct _send_
|
||||
{
|
||||
uint8_t device_id;
|
||||
uint8_t sn;
|
||||
uint8_t packet_index;
|
||||
uint8_t try_times;
|
||||
uint16_t address;
|
||||
uint16_t length;
|
||||
uint32_t next_try_time;
|
||||
}send_t;
|
||||
extern int ModbusM_init(void);
|
||||
extern int ModbusMastertRx(MODBUS_MASTERT_T *m,uint8 *rxbuf, uint8 len);
|
||||
extern void ModbusMastertPoll(MODBUS_MASTERT_T *m);
|
||||
extern int zb_ModBusWordWriteHook(unsigned short addr, unsigned short length);
|
||||
#endif
|
345
main/stm32/ModbusS.c
Normal file
345
main/stm32/ModbusS.c
Normal file
@ -0,0 +1,345 @@
|
||||
#include <string.h>
|
||||
#include "ModbusS.h"
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
static const uint8_t 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
|
||||
} ;
|
||||
/* CRC??????*/
|
||||
static const uint8_t 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
|
||||
} ;
|
||||
|
||||
uint16_t crc16(uint8_t *puchMsg, uint16_t usDataLen)
|
||||
{
|
||||
uint8_t uchCRCHi = 0xFF ; /* ?CRC????? */
|
||||
uint8_t uchCRCLo = 0xFF ; /* ?CRC ????? */
|
||||
uint32_t uIndex ; /* CRC?????? */
|
||||
while (usDataLen--) /* ??????? */
|
||||
{
|
||||
uIndex = uchCRCHi ^ *puchMsg++ ; /* ??CRC */
|
||||
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;
|
||||
uchCRCLo = auchCRCLo[uIndex] ;
|
||||
}
|
||||
return (uchCRCHi << 8 | uchCRCLo) ;
|
||||
}//uint16 crc16(uint8 *puchMsg, uint16 usDataLen)
|
||||
|
||||
|
||||
|
||||
#pragma pack(0x10)
|
||||
uint16_t gWordVar[gWORD_SIZE];
|
||||
uint8_t gBitVar[(gBIT_SIZE+7)/8];
|
||||
#pragma pack()
|
||||
|
||||
int isBitHI(uint16_t Add)
|
||||
{
|
||||
if(gBitVar[(Add)>>3] & (1<<((Add)&0x07)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ModBusBitWriteHook(uint16_t addr, uint16_t length)
|
||||
{
|
||||
}
|
||||
extern void reset_depth(void);
|
||||
uint16_t reboot_req ;
|
||||
extern uint16_t last_pile_id;
|
||||
extern int zb_ModBusWordWriteHook(uint16_t addr, uint16_t length);
|
||||
void ModBusWordWriteHook(uint16_t addr, uint16_t length)
|
||||
{
|
||||
|
||||
if(addr == RECORD_REG_ADDR && gWordVar[RECORD_REG_ADDR] == 0xffff){
|
||||
reset_depth();
|
||||
gWordVar[RECORD_REG_ADDR] = 0;
|
||||
}
|
||||
if(addr == DEPTH_RESET_ADDR && gWordVar[DEPTH_RESET_ADDR] == 0x5555){
|
||||
config_load();
|
||||
gWordVar[DEPTH_RESET_ADDR] = 0;
|
||||
}
|
||||
if(addr == DEPTH_RESET_ADDR && gWordVar[DEPTH_RESET_ADDR] == 0x55aa){
|
||||
gWordVar[RECORD_REG_ADDR] = 9999; //强制增加桩号
|
||||
reset_depth();
|
||||
gWordVar[DEPTH_RESET_ADDR] = 0;
|
||||
}
|
||||
if(addr == LAST_PILE_ID_ADDR){
|
||||
last_pile_id = gWordVar[LAST_PILE_ID_ADDR];
|
||||
}
|
||||
else if(addr == FLOW_CONFIG_ADDR && gWordVar[FLOW_CONFIG_ADDR] == 0x55aa){
|
||||
save_flow_cfg();
|
||||
}
|
||||
else if(addr == DEPTH_CONFIG_ADDR && gWordVar[DEPTH_CONFIG_ADDR] == 0x55aa){
|
||||
save_depth_cfg();
|
||||
}
|
||||
else if(addr == CAL_4_20MA_ADDR && gWordVar[CAL_4_20MA_ADDR] == 0x55aa){
|
||||
save_cal_4_20ma();
|
||||
}
|
||||
else if(addr == REBOOT_REW_ADDR ){
|
||||
if(gWordVar[REBOOT_REW_ADDR] == 0x55aa){
|
||||
reboot_req = 0x55aa;
|
||||
}
|
||||
else if(gWordVar[REBOOT_REW_ADDR] == 0x55ab){
|
||||
esp_restart();
|
||||
}
|
||||
else if(gWordVar[REBOOT_REW_ADDR] == 0xaa55){
|
||||
restore_default();
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
else{
|
||||
zb_ModBusWordWriteHook(addr,length);
|
||||
}
|
||||
}
|
||||
extern volatile int modbus_save_flg;
|
||||
|
||||
uint16_t modbus_addr = 1;
|
||||
int ModbusSlaveProcess(uint8_t *txbuf, uint8_t *rxbuf, uint16_t rxLen, int is_crc)
|
||||
{
|
||||
uint16_t crcData,crcChk;
|
||||
uint8_t Offset,ByteAdd;
|
||||
uint16_t ByteNumber;
|
||||
uint16_t add;
|
||||
uint16_t length;
|
||||
int out_len = 0;
|
||||
int i;
|
||||
uint8_t *pDat;
|
||||
uint16_t *pWordVar;
|
||||
if(rxLen<4)
|
||||
return 0;
|
||||
if((rxbuf[0]==modbus_addr) || (rxbuf[0]==255))
|
||||
{
|
||||
if(is_crc != 0)
|
||||
{
|
||||
crcData = rxbuf[rxLen-1]+(rxbuf[rxLen-2]<<8);
|
||||
crcChk = crc16(rxbuf,rxLen-2);
|
||||
if( crcData != crcChk)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
add = ((uint16_t)rxbuf[2]<<8)+ rxbuf[3];
|
||||
//if(Length !=
|
||||
length = (rxbuf[4]<<8) | rxbuf[5];
|
||||
|
||||
txbuf[0] = rxbuf[0];
|
||||
switch(rxbuf[1])
|
||||
{
|
||||
case 0x01: //Read Coils
|
||||
if((add+length) > gBIT_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x81;
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
out_len = 3;
|
||||
break;
|
||||
}
|
||||
txbuf[1]=0x01;
|
||||
ByteNumber = (length+7)/8;
|
||||
txbuf[2]= ByteNumber;
|
||||
ByteAdd = add>>3; //add/8
|
||||
Offset = add&0x07; //add%8
|
||||
for(i=0; i<(ByteNumber-1); i++)
|
||||
{
|
||||
txbuf[3+i] = gBitVar[ByteAdd+i]>>Offset;
|
||||
txbuf[3+i] |= gBitVar[ByteAdd+i+1]<<(8-Offset);
|
||||
}
|
||||
txbuf[3+ByteNumber-1] = gBitVar[ByteAdd+ByteNumber-1]>>Offset;
|
||||
txbuf[3+ByteNumber-1] &= 0xff>>Offset;
|
||||
out_len = ByteNumber+3;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x04: //Read Holding Registers
|
||||
if((add+length) > gWORD_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x80 + rxbuf[1];
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
out_len = 3;;
|
||||
break;
|
||||
}
|
||||
if(length > 512)
|
||||
{
|
||||
length = 512;
|
||||
}
|
||||
if(rxbuf[1]==4)
|
||||
{
|
||||
add += 64;
|
||||
}
|
||||
txbuf[1]=rxbuf[1];
|
||||
ByteNumber = length*2;
|
||||
txbuf[2]= ByteNumber&0xff;
|
||||
pDat = &txbuf[3];
|
||||
pWordVar = (uint16_t *)&gWordVar[add];
|
||||
for(i=0; i<length; i++)
|
||||
{
|
||||
*pDat++ = *pWordVar>>8;
|
||||
*pDat++ = *pWordVar&0xff;
|
||||
pWordVar++;
|
||||
}
|
||||
out_len = ByteNumber+3;
|
||||
break;
|
||||
case 0x05: //Write Single Coil
|
||||
if(add >= gBIT_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x85;
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
out_len = 3;
|
||||
break;
|
||||
}
|
||||
ByteAdd = add>>3; //same add/8
|
||||
Offset = add&0x07; //same add%8
|
||||
if(rxbuf[4] == 0)
|
||||
{
|
||||
clrBit(add);
|
||||
}
|
||||
else if(rxbuf[4] == 0xff)
|
||||
{
|
||||
setBit(add);
|
||||
}
|
||||
else
|
||||
{
|
||||
txbuf[1] = 0x85;
|
||||
txbuf[2] = 0x03; //ILLEGAL DATA VALUE
|
||||
out_len = 3;
|
||||
break;
|
||||
}
|
||||
memcpy(txbuf,rxbuf,6);
|
||||
ModBusBitWriteHook(add,1);
|
||||
out_len = 6;
|
||||
break;
|
||||
case 0x06: //Write Single Register
|
||||
if(add >= gWORD_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x86;
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
out_len = 3;
|
||||
break;
|
||||
}
|
||||
gWordVar[add] = (rxbuf[4]<<8)+rxbuf[5];
|
||||
memcpy(txbuf,rxbuf,6);
|
||||
ModBusWordWriteHook(add,1);
|
||||
out_len = 6;
|
||||
break;
|
||||
case 0x0F: //Write Multiple Coil
|
||||
if((add+length) > gBIT_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x8F;
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
out_len = 3;
|
||||
}
|
||||
|
||||
txbuf[1]=0x0F;
|
||||
txbuf[2] = rxbuf[2];
|
||||
txbuf[3] = rxbuf[3];
|
||||
txbuf[4] = 0;
|
||||
txbuf[5] = length&0xff;
|
||||
pDat = rxbuf+7;
|
||||
for(i=0; i<length; i++)
|
||||
{
|
||||
if(*(pDat+(i>>3)) & (1<<(i&0x07)))
|
||||
setBit(i+add);
|
||||
else
|
||||
clrBit(i+add);
|
||||
}
|
||||
ModBusBitWriteHook(add,length);
|
||||
out_len = 6;
|
||||
break;
|
||||
case 0x10: //Write Multiple registers
|
||||
if((add+length) > gWORD_SIZE)
|
||||
{
|
||||
txbuf[1] = 0x90;
|
||||
txbuf[2] = 0x02; //ILLEGAL DATA ADDRESS
|
||||
crcChk = crc16(txbuf,3);
|
||||
txbuf[3] = crcChk>>8;
|
||||
txbuf[4] = crcChk;
|
||||
out_len = 3;
|
||||
}
|
||||
txbuf[1]=0x10;
|
||||
txbuf[2] = rxbuf[2];
|
||||
txbuf[3] = rxbuf[3];
|
||||
txbuf[4]= 0;
|
||||
txbuf[5]= length&0xff;
|
||||
pDat = rxbuf+7;
|
||||
pWordVar = (uint16_t *)&gWordVar[add];
|
||||
{
|
||||
for(i=0; i<length; i++)
|
||||
{
|
||||
*pWordVar++ = (*pDat<<8)|*(pDat+1);
|
||||
pDat+=2;
|
||||
}
|
||||
}
|
||||
|
||||
ModBusWordWriteHook(add,length);
|
||||
out_len = 6;
|
||||
break;
|
||||
}//switch(rxbuf[1])
|
||||
|
||||
if(is_crc && out_len > 0)
|
||||
{
|
||||
crcChk = crc16(txbuf,out_len);
|
||||
txbuf[out_len++] = crcChk>>8;
|
||||
txbuf[out_len++] = crcChk & 0xff;
|
||||
}
|
||||
}
|
||||
return out_len;
|
||||
}
|
74
main/stm32/ModbusS.h
Normal file
74
main/stm32/ModbusS.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef _MODBUS_H
|
||||
#define _MODBUS_H
|
||||
#include<stdint.h>
|
||||
//#define uint8_t unsigned char
|
||||
//#define uint16_t unsigned short
|
||||
//#define uint32 unsigned int
|
||||
|
||||
#define setBit(Add) gBitVar[(Add)>>3] |= (1<<((Add)&0x07))
|
||||
#define clrBit(Add) gBitVar[(Add)>>3] &= ~(1<<((Add)&0x07))
|
||||
//#define ModBusTxData uart1_tx
|
||||
|
||||
extern uint16_t crc16(uint8_t *puchMsg, uint16_t usDataLen);
|
||||
extern int ModbusSlaveProcess(uint8_t *txbuf, uint8_t *rxbuf, uint16_t rxLen, int is_crc);
|
||||
|
||||
|
||||
|
||||
|
||||
int isBitHI(uint16_t Add);
|
||||
void xorBit(uint16_t Add);
|
||||
|
||||
void WriteBit(uint16_t Add,uint8_t bit_value);
|
||||
#define gBIT_SIZE 128
|
||||
#define gWORD_SIZE 512
|
||||
extern uint8_t gBitVar[(gBIT_SIZE+7)/8];
|
||||
extern uint16_t gWordVar[gWORD_SIZE];
|
||||
extern uint16_t modbus_addr;
|
||||
|
||||
// #include "usart.h"
|
||||
// #include "gpio.h"
|
||||
// #include "main.h"
|
||||
#define BUFFER_SIZE 2000
|
||||
extern uint8_t rx_buffer[256];
|
||||
extern uint8_t tx_buffer[256];
|
||||
extern uint16_t rx_buff_len;
|
||||
// extern __IO uint8_t recv_end_flag;
|
||||
extern uint8_t recv_end_flag;
|
||||
extern void modbus_recv_mode(void);
|
||||
extern void usart2_dma_recv_start(void);
|
||||
extern void modbus_send(uint8_t *buf, uint8_t len);
|
||||
// extern void save_flow_cfg(void);
|
||||
extern int check_mastrt_recv(void);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// #ifndef _MODBUS_H
|
||||
// #define _MODBUS_H
|
||||
// #include <stdint.h>
|
||||
// #define uint8_t unsigned char
|
||||
// #define uint16_t unsigned short
|
||||
// #define uint32 unsigned int
|
||||
|
||||
// #define setBit(Add) gBitVar[(Add) >> 3] |= (1 << ((Add)&0x07))
|
||||
// #define clrBit(Add) gBitVar[(Add) >> 3] &= ~(1 << ((Add)&0x07))
|
||||
// //#define ModBusTxData uart1_tx
|
||||
|
||||
// extern uint16_t crc16(uint8_t *puchMsg, uint16_t usDataLen);
|
||||
// extern int ModbusSlaveProcess(uint8_t *txbuf, uint8_t *rxbuf, uint16_t rxLen, int is_crc);
|
||||
|
||||
|
||||
|
||||
// int isBitHI(uint16_t Add);
|
||||
// void xorBit(uint16_t Add);
|
||||
|
||||
// void WriteBit(uint16_t Add, uint8_t bit_value);
|
||||
// #define gBIT_SIZE 128
|
||||
// #define gWORD_SIZE 12288
|
||||
// extern uint8_t gBitVar[(gBIT_SIZE + 7) / 8];
|
||||
// extern uint16_t gWordVar[gWORD_SIZE];
|
||||
|
||||
// void modbus(void);
|
||||
// void rs485_send(void *buf, uint16_t len);
|
||||
|
||||
// #endif
|
516
main/stm32/ads1220.c
Normal file
516
main/stm32/ads1220.c
Normal file
@ -0,0 +1,516 @@
|
||||
#include "ads1220.h"
|
||||
// #include "main.h"
|
||||
#include "config.h"
|
||||
#include "ModbusS.h"
|
||||
#include "ModbusM.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "driver/mcpwm.h"
|
||||
|
||||
#define TAG "ADS1220"
|
||||
|
||||
#define ADS1220_HOST SPI2_HOST
|
||||
|
||||
#define SPI2_PIN_NUM_MISO 40
|
||||
#define SPI2_PIN_NUM_MOSI 41
|
||||
#define SPI2_PIN_NUM_CLK 37
|
||||
#define SPI2_PIN_NUM_CS 38
|
||||
|
||||
#define PIN_NUM_DC 9
|
||||
#define PIN_NUM_RST 4
|
||||
#define PIN_NUM_BCKL 5
|
||||
|
||||
// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
|
||||
// but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
|
||||
#define PARALLEL_LINES 16
|
||||
static spi_device_handle_t spi2;
|
||||
|
||||
/***************************************************
|
||||
*
|
||||
*ADS1220<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
*1.<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ADS1220<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŷ˿<EFBFBD>
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
/****************ADS1220<32><30><EFBFBD>ź궨<C5BA><EAB6A8>*******************/
|
||||
#define ADS1220_nCS_HIGH() gpio_set_level(GPIO_NUM_38, 1)
|
||||
#define ADS1220_nCS_LOW() gpio_set_level(GPIO_NUM_38, 0)
|
||||
|
||||
/*****************************************************/
|
||||
#define ADS1220_CMD_WREG 0x40 // д<>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define ADS1220_CMD_RREG 0x20 // <20><><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define ADS1220_CMD_RESET 0x06 // <20><>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>
|
||||
#define ADS1220_CMD_START 0x08 // <20><>ʼת<CABC><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define ADS1220_CMD_POWERDOWN 0x02 // <20><EFBFBD><CDB9>ĵ<EFBFBD><C4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define ADS1220_CMD_RDATA 0x10 // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
#define Channal1 0x00 // ͨ<><CDA8>1
|
||||
#define Channal2 0x10 // ͨ<><CDA8>2
|
||||
#define Channal3 0x20 // ͨ<><CDA8>3
|
||||
#define Channal4 0x30 // ͨ<><CDA8>4
|
||||
|
||||
#define ADS1220_REG0 0x00 // <20>Ĵ<EFBFBD><C4B4><EFBFBD> 0
|
||||
#define ADS1220_REG1 0x01 // <20>Ĵ<EFBFBD><C4B4><EFBFBD> 1
|
||||
#define ADS1220_REG2 0x02 // <20>Ĵ<EFBFBD><C4B4><EFBFBD> 2
|
||||
#define ADS1220_REG3 0x03 // <20>Ĵ<EFBFBD><C4B4><EFBFBD> 3
|
||||
|
||||
#define PGAGain1 0x00 // PGA<47><41><EFBFBD><EFBFBD> Ĭ<><C4AC>
|
||||
#define PGAGain2 0x02 //
|
||||
#define PGAGain4 0x04 //
|
||||
#define PGAGain8 0x06 //
|
||||
#define PGAGain16 0x08 //
|
||||
#define PGAGain32 0x0A //
|
||||
#define PGAGain64 0x0C //
|
||||
#define PGAGain128 0x0E //
|
||||
|
||||
#define ADS1220_Standby 0 // ת<><D7AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
#define ADS1220_ConvStart 1 // ת<><D7AA><EFBFBD><EFBFBD>ʼ
|
||||
#define ADS1220_ConvFinish 2 // ת<><D7AA><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
||||
#define ADS1220_Channal1 0 // ͨ<><CDA8>1
|
||||
#define ADS1220_Channal2 1 // ͨ<><CDA8>2
|
||||
#define ADS1220_Channal3 2 // ͨ<><CDA8>3
|
||||
#define ADS1220_Channal4 3 // ͨ<><CDA8>4
|
||||
|
||||
#define LED1_GPIO_PIN 11
|
||||
#define LED2_GPIO_PIN 12
|
||||
|
||||
#define GPIO_OUTPUT_PIN_SEL ((1ULL << LED1_GPIO_PIN) | (1ULL << LED2_GPIO_PIN))
|
||||
|
||||
#define GPIO_INPUT_IO_39 39
|
||||
#define GPIO_INPUT_PIN_SEL (1ULL << GPIO_INPUT_IO_39)
|
||||
// #define GPIO_INPUT_IO_1 5
|
||||
// #define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
|
||||
#define ESP_INTR_FLAG_DEFAULT 0
|
||||
int ads1220_watchdog = 0;
|
||||
|
||||
extern xQueueHandle gpio_evt_queue;
|
||||
|
||||
xQueueHandle gpio_evt_queue = NULL;
|
||||
uint16_t gWordVar[gWORD_SIZE];
|
||||
int ad_value[4];
|
||||
uint32_t ad_update_time[4];
|
||||
uint8_t ad_watchdog_cnt = 0;
|
||||
extern flow_t *pflow;
|
||||
const uint8_t ch_cmd[4] = {0x0C, 0xA1, 0x0C, 0xB1}; //
|
||||
|
||||
static int ch = 0;
|
||||
|
||||
void ADS1220_Init(void)
|
||||
{
|
||||
// ESP_LOGI(TAG, "Start init ADS1220.\n");
|
||||
ADS1220_Config();
|
||||
// ESP_LOGI(TAG, "Start ADS1220_Config.\n");
|
||||
ch = 0;
|
||||
|
||||
ADS1220_WriteReg(ADS1220_REG0, ch_cmd[0]);
|
||||
ADS1220_WriteCommand(ADS1220_CMD_START);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR ads1220_done_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig,
|
||||
const cap_event_data_t *edata, void *arg)
|
||||
{
|
||||
// uint32_t gpio_num = (uint32_t)arg;
|
||||
// if (ch == 1)
|
||||
// {
|
||||
// pflow[0].update_time = xTaskGetTickCount();
|
||||
// }
|
||||
// if (ch == 3)
|
||||
// {
|
||||
// pflow[1].update_time = xTaskGetTickCount();
|
||||
// }
|
||||
ad_update_time[ch] = edata->cap_value;
|
||||
xQueueSendFromISR(gpio_evt_queue, &ad_update_time[ch], NULL);
|
||||
}
|
||||
|
||||
static void GPIO_Init(void)
|
||||
{
|
||||
// zero-initialize the config structure.
|
||||
gpio_config_t io_conf = {};
|
||||
// disable interrupt
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
// set as output mode
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
// bit mask of the pins that you want to set,e.g.GPIO18/19
|
||||
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
|
||||
// disable pull-down mode
|
||||
io_conf.pull_down_en = 0;
|
||||
// disable pull-up mode
|
||||
io_conf.pull_up_en = 0;
|
||||
// configure GPIO with the given settings
|
||||
gpio_config(&io_conf);
|
||||
|
||||
// interrupt of rising edge
|
||||
// io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||
// // bit mask of the pins, use GPIO4/5 here
|
||||
// io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
|
||||
// // set as input mode
|
||||
// io_conf.mode = GPIO_MODE_INPUT;
|
||||
// // enable pull-up mode
|
||||
// io_conf.pull_up_en = 1;
|
||||
// gpio_config(&io_conf);
|
||||
|
||||
// change gpio intrrupt type for one pin
|
||||
// gpio_set_intr_type(GPIO_INPUT_IO_39, GPIO_INTR_NEGEDGE);
|
||||
|
||||
// create a queue to handle gpio event from isr
|
||||
gpio_evt_queue = xQueueCreate(1, sizeof(uint32_t));
|
||||
// install gpio isr service
|
||||
// gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
|
||||
// // hook isr handler for specific gpio pin
|
||||
// gpio_isr_handler_add(GPIO_INPUT_IO_39, gpio_isr_handler, (void *)GPIO_INPUT_IO_39);
|
||||
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_1, GPIO_INPUT_IO_39));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pullup_en(GPIO_INPUT_IO_39));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = ads1220_done_handler, // 绑定深度中断处理函数
|
||||
.user_data = NULL};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, &conf));
|
||||
}
|
||||
|
||||
uint8_t ret = 0;
|
||||
|
||||
/****
|
||||
* ADS1220<EFBFBD><EFBFBD><EFBFBD>Ĵ<EFBFBD><EFBFBD><EFBFBD>
|
||||
**/
|
||||
u8 ADS1220_ReadReg(u8 reg)
|
||||
{
|
||||
u8 Val;
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t)); // Zero out the transaction
|
||||
t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
|
||||
t.tx_data[0] = ADS1220_CMD_RREG | ((reg & 0x03) << 2);
|
||||
t.length = 2 * 8;
|
||||
ret = spi_device_polling_transmit(spi2, &t); // Transmit!
|
||||
assert(ret == ESP_OK);
|
||||
Val = t.rx_data[1];
|
||||
return Val;
|
||||
}
|
||||
/***
|
||||
* <EFBFBD><EFBFBD>ADS1220<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD>24Bits
|
||||
*
|
||||
**/
|
||||
|
||||
// static u32 ADS1220_ReadWrite24Bits(u32 dat)
|
||||
// {
|
||||
// uint8_t tmp[3];
|
||||
// static int val = 0;
|
||||
|
||||
// HAL_SPI_TransmitReceive(&spi2, (uint8_t *)&dat, (uint8_t *)tmp, 3, 500);
|
||||
|
||||
// val = ((uint32_t)tmp[0] << 16) + ((uint32_t)tmp[1] << 8) + ((uint32_t)tmp[2] << 0);
|
||||
|
||||
// // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ 23λ <20><>1 <20><>Ϊ <20>з<EFBFBD><D0B7><EFBFBD>
|
||||
// if (val & 0x800000)
|
||||
// {
|
||||
// val |= 0xFF000000;
|
||||
// }
|
||||
// return val;
|
||||
// }
|
||||
|
||||
// ADS1220<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
s32 ADS1220_ReadData(void)
|
||||
{
|
||||
s32 Val = 0;
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t)); // Zero out the transaction
|
||||
t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
|
||||
t.tx_data[0] = ADS1220_CMD_RDATA;
|
||||
t.length = 4 * 8; // Command is 24 bits
|
||||
ret = spi_device_polling_transmit(spi2, &t); // Transmit!
|
||||
assert(ret == ESP_OK);
|
||||
Val = (t.rx_data[1] << 16) | (t.rx_data[2] << 8) | t.rx_data[3];
|
||||
if (Val & 0x800000)
|
||||
{
|
||||
Val |= 0xFF000000;
|
||||
}
|
||||
return Val;
|
||||
}
|
||||
// ADS1220д<30>Ĵ<EFBFBD><C4B4><EFBFBD>
|
||||
void ADS1220_WriteReg(u8 reg, u8 dat)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t)); // Zero out the transaction
|
||||
t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
|
||||
// t.flags = SPI_TRANS_USE_TXDATA;
|
||||
t.tx_data[0] = ADS1220_CMD_WREG | ((reg & 0x03) << 2);
|
||||
t.tx_data[1] = dat;
|
||||
t.length = 2 * 8; // Command is 16 bits
|
||||
ret = spi_device_polling_transmit(spi2, &t); // Transmit!
|
||||
assert(ret == ESP_OK);
|
||||
}
|
||||
|
||||
// ADS1220д<30><D0B4><EFBFBD><EFBFBD>
|
||||
void ADS1220_WriteCommand(u8 cmd)
|
||||
{
|
||||
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t)); // Zero out the transaction
|
||||
t.flags = SPI_TRANS_USE_TXDATA | SPI_TRANS_USE_RXDATA;
|
||||
t.length = 8 * 2; // Command is 8 bits
|
||||
t.tx_data[0] = cmd; // The data is the cmd itself
|
||||
// ESP_LOGI(TAG, "spi_device_polling_transmit befor.\n");
|
||||
ret = spi_device_polling_transmit(spi2, &t); // Transmit!
|
||||
// ESP_LOGI(TAG, "spi_device_polling_transmit after.\n");
|
||||
assert(ret == ESP_OK);
|
||||
// // ADS1220_CS=0;
|
||||
// ADS1220_nCS_LOW();
|
||||
// ADS1220_ReadWriteByte(cmd);
|
||||
// // ADS1220_CS=1;
|
||||
// ADS1220_nCS_HIGH();
|
||||
}
|
||||
|
||||
// ADS1220<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
void ADS1220_PowerDown(void)
|
||||
{
|
||||
ADS1220_WriteCommand(ADS1220_CMD_POWERDOWN); //
|
||||
}
|
||||
|
||||
// ADS1220<32><30><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
void ADS1220_StartConv(u8 channal)
|
||||
{
|
||||
/*
|
||||
u8 val ;
|
||||
val = ADS1220_ReadReg(ADS1220_REG0);
|
||||
|
||||
ADS1220.CurrentCH = ADS1220_Channal1;
|
||||
val = val & 0x0f | Channal1;
|
||||
ADS1220_WriteReg(ADS1220_REG0, val ); // <20>Ĵ<EFBFBD><C4B4><EFBFBD>0 <20><><EFBFBD><EFBFBD>: AIN P = AIN0, AIN N = AIN1 <20><><EFBFBD>ģʽ ʹ<><CAB9>PGA 64 (110) <20><><EFBFBD><EFBFBD>PGA (0)
|
||||
*/
|
||||
ADS1220_WriteCommand(ADS1220_CMD_START); // <20><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
}
|
||||
|
||||
// ADS1220<32><30>λ
|
||||
void ADS1220_Reset(void)
|
||||
{
|
||||
ADS1220_WriteCommand(ADS1220_CMD_RESET); // <20><>λADS1220
|
||||
}
|
||||
|
||||
// ADS1220 PGA<47><41><EFBFBD><EFBFBD>
|
||||
void ADS1220_PGASet(u8 gain)
|
||||
{
|
||||
u8 val;
|
||||
val = ADS1220_ReadReg(ADS1220_REG0);
|
||||
val = (val & 0xF1) | gain;
|
||||
|
||||
ADS1220_WriteReg(ADS1220_REG0, val);
|
||||
// val = ADS1220_ReadReg(ADS1220_REG0);
|
||||
ADS1220_StartConv(ADS1220_Channal1); // <20><><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
}
|
||||
// static uint8_t dara_rate = 0x40;
|
||||
void ADS1220_Config(void)
|
||||
{
|
||||
static uint8_t read[4];
|
||||
ADS1220_WriteCommand(ADS1220_CMD_RESET); // <20><>λADS1220
|
||||
vTaskDelay(10);
|
||||
// ESP_LOGI(TAG, "ADS1220_WriteCommand.\n");
|
||||
ADS1220_WriteReg(ADS1220_REG0, 0xa0); // <20>Ĵ<EFBFBD><C4B4><EFBFBD>0 <20><><EFBFBD><EFBFBD>: <20><><EFBFBD><EFBFBD>: AIN P = AIN0, AIN N = AVSS <20><><EFBFBD><EFBFBD>ģʽ ʹ<><CAB9>PGA1 (100) <20><><EFBFBD><EFBFBD>PGA(0)
|
||||
|
||||
ADS1220_WriteReg(ADS1220_REG1, 0x00); // <20>Ĵ<EFBFBD><C4B4><EFBFBD>1 <20><><EFBFBD><EFBFBD>: Turboģʽ 40.SPS(00000)<29><>ʹ<EFBFBD><CAB9><EFBFBD>¶ȴ<C2B6><C8B4><EFBFBD><EFBFBD><EFBFBD>(0) <20>رյ<D8B1><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(0)
|
||||
|
||||
ADS1220_WriteReg(ADS1220_REG2, 0x20); // <20>Ĵ<EFBFBD><C4B4><EFBFBD>2 <20><><EFBFBD><EFBFBD>: <20><>ѹ<EFBFBD><D1B9> <20>ڲ<EFBFBD>2.048-v<>ο<EFBFBD>(00) ʹ<><CAB9>оƬFIR<49>˲<EFBFBD>50Hz(10) <20><><EFBFBD><EFBFBD>Դ0ma // Low-side<64><65>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD> Ĭ<><C4AC>(0) <20><><EFBFBD><EFBFBD>Դ <20>ر<EFBFBD>
|
||||
ADS1220_WriteReg(ADS1220_REG3, 0x00); // <20>Ĵ<EFBFBD><C4B4><EFBFBD>3 <20><><EFBFBD><EFBFBD>: : IDAC1 connect to AIN2 : IDAC2 disabled
|
||||
|
||||
read[0] = ADS1220_ReadReg(ADS1220_REG0);
|
||||
read[1] = ADS1220_ReadReg(ADS1220_REG1);
|
||||
read[2] = ADS1220_ReadReg(ADS1220_REG2);
|
||||
read[3] = ADS1220_ReadReg(ADS1220_REG3);
|
||||
printf("ads1220 reg %02x %02x %02x %02x \n", read[0], read[1], read[2], read[3]);
|
||||
}
|
||||
|
||||
void LED2_Toggle(void)
|
||||
{
|
||||
static unsigned char flg = 1;
|
||||
if (flg)
|
||||
{
|
||||
gpio_set_level(LED2_GPIO_PIN, 0);
|
||||
flg = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpio_set_level(LED2_GPIO_PIN, 1);
|
||||
flg = 1;
|
||||
}
|
||||
}
|
||||
static void SPI2_Init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
spi_bus_config_t buscfg2 = {
|
||||
.miso_io_num = SPI2_PIN_NUM_MISO,
|
||||
.mosi_io_num = SPI2_PIN_NUM_MOSI,
|
||||
.sclk_io_num = SPI2_PIN_NUM_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 8};
|
||||
|
||||
spi_device_interface_config_t devcfg2 = {
|
||||
.clock_speed_hz = 1 * 1000 * 1000, // Clock out at 1 MHz
|
||||
.mode = 0, // SPI mode 0
|
||||
.cs_ena_posttrans = 2, // Keep the CS low 2 cycles after transaction, to stop slave from missing the last bit when CS has less propagation delay than SPI CLK
|
||||
.spics_io_num = SPI2_PIN_NUM_CS, // CS pin
|
||||
.queue_size = 1, // We want to be able to queue 7 transactions at a time
|
||||
// .address_bits = 8,
|
||||
// .pre_cb = lcd_spi_pre_transfer_callback, // Specify pre-transfer callback to handle D/C line
|
||||
// .command_bits = 8,
|
||||
};
|
||||
// Initialize the SPI bus
|
||||
ret = spi_bus_initialize(ADS1220_HOST, &buscfg2, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
// Attach the ADS1220 to the SPI bus
|
||||
ret = spi_bus_add_device(ADS1220_HOST, &devcfg2, &spi2);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
extern void zero_totalflow(int ch);
|
||||
|
||||
extern int zero_totalflow_req;
|
||||
extern int abs_sub(uint32_t enc_update_time, uint32_t _enc_update_time);
|
||||
extern cal_4_20ma_t *cal_4_20ma;
|
||||
extern flow_config_t *flow_config;
|
||||
extern flow_t *pflow;
|
||||
extern uint8_t timeout[2];
|
||||
extern int flow_rem[2];
|
||||
void ads1220_task(void)
|
||||
{
|
||||
uint32_t io_num;
|
||||
u32 data;
|
||||
static uint32_t ad_flow_tick = 10;
|
||||
while (1)
|
||||
{
|
||||
// ESP_LOGI(TAG, "xQueueReceive before\n ");
|
||||
if (xQueueReceive(gpio_evt_queue, &io_num, 200))
|
||||
{
|
||||
int ad_ch;
|
||||
// ESP_LOGI(TAG, "xQueueReceive during\n ");
|
||||
ads1220_watchdog = 0;
|
||||
int ad_raw = ADS1220_ReadData();
|
||||
// ESP_LOGI(TAG, "ad_raw : %d\n ", ad_raw);
|
||||
ad_value[ch] = ad_raw / 128;
|
||||
ad_ch = ch;
|
||||
gWordVar[AD_RAW_REG_ADDR + ch] = ad_value[ch] / 2;
|
||||
// ESP_LOGI(TAG, "channel : %d ad_value: %d\n ", ch, ad_value[ch]);
|
||||
ch++;
|
||||
if (ch >= sizeof(ch_cmd))
|
||||
{
|
||||
ch = 0;
|
||||
}
|
||||
ADS1220_WriteReg(ADS1220_REG0, ch_cmd[ch]);
|
||||
ADS1220_WriteCommand(ADS1220_CMD_START);
|
||||
ad_watchdog_cnt = 0;
|
||||
LED2_Toggle();
|
||||
if ((ad_ch == 1 || ad_ch == 3) && flow_config->input_type == 1)
|
||||
{
|
||||
int flow_ch = ad_ch / 2;
|
||||
int time_diff = abs_sub(ad_update_time[ad_ch], pflow[flow_ch].update_time);
|
||||
ad_flow_cal_t *cal = flow_config->ad_cal;
|
||||
int t_flow; // time_diff时间段总流量
|
||||
pflow[flow_ch].flow_ = scale(ad_value[ad_ch], cal_4_20ma->ch[flow_ch].ad_4ma, cal_4_20ma->ch[flow_ch].ad_20ma, cal[flow_ch].flow_min, cal[flow_ch].flow_max);
|
||||
if (pflow[flow_ch].flow_ < flow_config->min_flow[flow_ch]) // 小流量切除
|
||||
{
|
||||
pflow[flow_ch].flow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pflow[flow_ch].flow = pflow[flow_ch].flow_;
|
||||
}
|
||||
// 累计流量计算 pflow[i].flow 单位为0.01L/分钟 time_diff 单位为1us
|
||||
// flow = pflow[i].flow / 60.0 * 10000; 将流量换算成uL/s
|
||||
// t_diff = time_diff / 1000 将时间差换算成秒
|
||||
// t_flow = flow * t_diff 计算t_diff时间段的流量 单位uL
|
||||
// 取出0.01L的整数部分累加,余数部分和下次值累加
|
||||
// t_flow = pflow[i].flow * 1000 * time_diff / 1000000 / 60;
|
||||
int time_diff_us = time_diff / (APB_CLK_FREQ / 1000000);
|
||||
t_flow = pflow[flow_ch].flow * (long long)time_diff_us / 60 / 100; //(5 * 60);
|
||||
flow_rem[flow_ch] += t_flow;
|
||||
int sub_flow = flow_rem[flow_ch] / 10000;
|
||||
pflow[flow_ch].total_flow += sub_flow;
|
||||
flow_rem[flow_ch] = flow_rem[flow_ch] - sub_flow * 10000;
|
||||
pflow[flow_ch].update_time = ad_update_time[ad_ch];
|
||||
timeout[flow_ch] = 0;
|
||||
// ESP_LOGI(TAG, "(type1) flow_rem[%d].flow: %u time_diff=%d", flow_ch ,pflow[flow_ch].flow,time_diff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ADS1220_Init();
|
||||
}
|
||||
if (zero_totalflow_req)
|
||||
{
|
||||
zero_totalflow_req = 0;
|
||||
zero_totalflow(0);
|
||||
zero_totalflow(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ads1220_task_start(void)
|
||||
{
|
||||
SPI2_Init();
|
||||
GPIO_Init();
|
||||
ADS1220_Init();
|
||||
xTaskCreate(ads1220_task, "ads1220_task", 4096, NULL, 10, NULL);
|
||||
}
|
||||
|
||||
// void ADS1220_set_rate(int i)
|
||||
//{
|
||||
// switch (i)
|
||||
// {
|
||||
// case 1 :dara_rate = 0x00;//20SPS
|
||||
// break;
|
||||
// case 2 :dara_rate = 0x20;//45SPS
|
||||
// break;
|
||||
// case 3 :dara_rate = 0x40;//90SPS
|
||||
// break;
|
||||
// case 4 :dara_rate = 0x60;//175SPS
|
||||
// break;
|
||||
// default:dara_rate = 0x00;//20SPS
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// int ADS1220_get_rate(void)
|
||||
//{
|
||||
// switch (dara_rate)
|
||||
// {
|
||||
// case 0x00 :return 20*100;//20SPS
|
||||
// break;
|
||||
// case 0x20 :return 45*100;//45SPS
|
||||
// break;
|
||||
// case 0x40 :return 90*100;//90SPS
|
||||
// break;
|
||||
// case 0x60 :return 175*100;//175SPS
|
||||
// break;
|
||||
// default:return 20*100;//20SPS
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// ch0 0.5V 3478
|
||||
// ch0 1.0V 0
|
||||
// ch0 1.5V 10429
|
||||
|
||||
// ch1 4.000ma 12783
|
||||
// ch1 12.00ma 38349
|
||||
|
||||
// ch2 4.000ma 12764
|
||||
// ch2 12.00ma 38336
|
61
main/stm32/ads1220.h
Normal file
61
main/stm32/ads1220.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef __ADS1220_H
|
||||
#define __ADS1220_H
|
||||
// #include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint32_t u32;
|
||||
typedef int32_t s32;
|
||||
#define LED1_GPIO_PIN 11
|
||||
#define LED2_GPIO_PIN 12
|
||||
|
||||
#define GPIO_INPUT_IO_39 39
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
int ch0_4ma;
|
||||
int ch0_12ma;
|
||||
float ch0_4ma_yl;
|
||||
float ch0_12ma_yl;
|
||||
|
||||
int ch1_4ma;
|
||||
int ch1_12ma;
|
||||
float ch1_4ma_yl;
|
||||
float ch1_12ma_yl;
|
||||
|
||||
int ch2_4ma;
|
||||
int ch2_12ma;
|
||||
float ch2_4ma_yl;
|
||||
float ch2_12ma_yl;
|
||||
}ads_cali_t;
|
||||
|
||||
//extern ads_cali_t ads_cali;
|
||||
|
||||
|
||||
uint32_t get_now_20us(void);
|
||||
int32_t tim_diff(uint32_t a,uint32_t b);
|
||||
int ADS1220_get_rate(void);
|
||||
void ADS1220_set_rate(int i);
|
||||
void ADS1220_Init(void); // ADS1220<32><30>ʼ<EFBFBD><CABC>
|
||||
void ADS1220_Config(void); // ADS1220<32><30><EFBFBD><EFBFBD>
|
||||
void ADS1220_StartConv(u8 channal); // ADS1220<32><30><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>
|
||||
void ADS1220_Reset(void); // ADS1220<32><30>λ
|
||||
void ADS1220_PowerDown(void); // ADS1220<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ
|
||||
void ADS1220_PGASet(u8 gain); // ADS1220 PGA<47><41><EFBFBD><EFBFBD>
|
||||
void ADS1220_WriteCommand(u8 cmd); // ADS1220д<30><D0B4><EFBFBD><EFBFBD>
|
||||
s32 ADS1220_ReadData(void); // ADS1220<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
void ADS1220_WriteReg(u8 reg,u8 dat); // ADS1220д<30>Ĵ<EFBFBD><C4B4><EFBFBD>
|
||||
u8 ADS1220_ReadReg(u8 reg); // ADS1220<32><30><EFBFBD>Ĵ<EFBFBD><C4B4><EFBFBD>
|
||||
u8 ADS1220_ReadWriteByte(u8 dat); // <20><>SPI<50><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>һ<EFBFBD>ֽ<EFBFBD>
|
||||
u32 ADS1220_ReadWrite24Bits(u32 dat); // <20><>ADS1220<32><30><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>24Bits
|
||||
|
||||
int scale(int raw, int raw_min, int raw_max,int eng_min, int eng_max);
|
||||
#endif
|
295
main/stm32/bl0939.c
Normal file
295
main/stm32/bl0939.c
Normal file
@ -0,0 +1,295 @@
|
||||
#include "bl0939.h"
|
||||
#include "string.h"
|
||||
#include "utils.h"
|
||||
// #include "ModbusS.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#define TAG "BL0939"
|
||||
|
||||
#define BL0939_HOST SPI3_HOST
|
||||
|
||||
#define SPI1_PIN_NUM_MISO 6
|
||||
#define SPI1_PIN_NUM_MOSI 5
|
||||
#define SPI1_PIN_NUM_CLK 4
|
||||
#define SPI1_PIN_NUM_CS 42
|
||||
|
||||
#define PIN_NUM_DC 9
|
||||
#define PIN_NUM_RST 4
|
||||
#define PIN_NUM_BCKL 5
|
||||
|
||||
extern move_t *pMoveCtx;
|
||||
// To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
|
||||
// but less overhead for setting up / finishing transfers. Make sure 240 is dividable by this.
|
||||
#define PARALLEL_LINES 16
|
||||
static spi_device_handle_t spi1;
|
||||
|
||||
static void SPI1_Init(void)
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
spi_bus_config_t buscfg1 = {
|
||||
.miso_io_num = SPI1_PIN_NUM_MISO,
|
||||
.mosi_io_num = SPI1_PIN_NUM_MOSI,
|
||||
.sclk_io_num = SPI1_PIN_NUM_CLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = PARALLEL_LINES * 320 * 2 + 8};
|
||||
|
||||
spi_device_interface_config_t devcfg1 = {
|
||||
#ifdef CONFIG_LCD_OVERCLOCK
|
||||
.clock_speed_hz = 26 * 1000 * 1000, // Clock out at 26 MHz
|
||||
#else
|
||||
.clock_speed_hz = 8 * 100 * 1000, // Clock out at 800kHz
|
||||
#endif
|
||||
|
||||
.mode = 1, // SPI mode 1
|
||||
.spics_io_num = SPI1_PIN_NUM_CS, // CS pin
|
||||
.queue_size = 7, // We want to be able to queue 7 transactions at a time
|
||||
// .command_bits = 8,
|
||||
// .pre_cb = lcd_spi_pre_transfer_callback, // Specify pre-transfer callback to handle D/C line
|
||||
};
|
||||
// Initialize the SPI bus
|
||||
ret = spi_bus_initialize(BL0939_HOST, &buscfg1, SPI_DMA_CH_AUTO);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
// Attach the ADS1220 to the SPI bus
|
||||
ret = spi_bus_add_device(BL0939_HOST, &devcfg1, &spi1);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void bl0939_spi_reset(void);
|
||||
|
||||
static void BL0939_SPI_TransmitReceive(uint8_t *tbuff, uint8_t *rbuff,
|
||||
uint16_t len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
spi_transaction_t t;
|
||||
memset(&t, 0, sizeof(t)); // Zero out the transaction
|
||||
t.tx_buffer = tbuff;
|
||||
t.rx_buffer = rbuff;
|
||||
t.length = len * 8; // Command is 16 bits
|
||||
ret = spi_device_polling_transmit(spi1, &t); // Transmit!
|
||||
assert(ret == ESP_OK);
|
||||
}
|
||||
|
||||
static uint32_t bl0939_read_reg(uint8_t reg)
|
||||
{
|
||||
uint8_t tx_buf[6] = {0x55, reg, 0, 0, 0, 0};
|
||||
uint8_t rx_buf[6] = {0};
|
||||
// bl0939_spi_reset();
|
||||
BL0939_SPI_TransmitReceive(tx_buf, rx_buf, 6);
|
||||
if (rx_buf[5] == (uint8_t) ~(0x55 + reg + rx_buf[2] + rx_buf[3] + rx_buf[4]))
|
||||
{
|
||||
return (uint32_t)rx_buf[2] << 16 |
|
||||
(uint32_t)rx_buf[3] << 8 |
|
||||
(uint32_t)rx_buf[4] << 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t r_temp = 0;
|
||||
static int bl0939_write_reg(uint8_t reg, uint32_t val, int check)
|
||||
{
|
||||
int i = 5;
|
||||
uint8_t h = val >> 16;
|
||||
uint8_t m = val >> 8;
|
||||
uint8_t l = val >> 0;
|
||||
do
|
||||
{
|
||||
i--;
|
||||
vTaskDelay(5);
|
||||
// bl0939_spi_reset();
|
||||
uint8_t tx_buf[6] = {0xA5, reg, h, m, l, ~(0XA5 + reg + h + m + l)};
|
||||
uint8_t rx_buf[6] = {0};
|
||||
BL0939_SPI_TransmitReceive(tx_buf, rx_buf, 6);
|
||||
vTaskDelay(10);
|
||||
if (0 == check)
|
||||
return 0;
|
||||
r_temp = bl0939_read_reg(reg);
|
||||
if (r_temp == val)
|
||||
return 0;
|
||||
} while (i > 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bl0939_spi_reset(void)
|
||||
{
|
||||
uint8_t tx_buf[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
uint8_t rx_buf[6] = {0};
|
||||
BL0939_SPI_TransmitReceive(tx_buf, rx_buf, 6);
|
||||
}
|
||||
|
||||
uint32_t comp_threshold(float mA)
|
||||
{
|
||||
return (uint32_t)(mA * 1 * 324004 * 0.00140625f * 0.95f / (600 * 1.218f));
|
||||
}
|
||||
|
||||
void bl0939_reset(void)
|
||||
{
|
||||
bl0939_spi_reset();
|
||||
bl0939_write_reg(0x19, 0x005a5a5a, 0); // <20><>λ<EFBFBD>û<EFBFBD><C3BB>Ĵ<EFBFBD><C4B4><EFBFBD>
|
||||
bl0939_write_reg(0x1a, 0x00000055, 1); // <20><><EFBFBD>д<EFBFBD><D0B4><EFBFBD><EFBFBD>
|
||||
bl0939_write_reg(0x10, 0xffff, 0); // Threshold A
|
||||
bl0939_write_reg(0x1E, 0xffff, 1); // Threshold B
|
||||
bl0939_write_reg(0x18, 0x00002000, 1); // cf
|
||||
bl0939_write_reg(0x1B, 0x000047ff, 0); // cf
|
||||
bl0939_write_reg(0x1a, 0x00000000, 1); // д<><D0B4><EFBFBD><EFBFBD>
|
||||
}
|
||||
|
||||
// T = 40ms
|
||||
int bl0939_get_current_A()
|
||||
{
|
||||
bl0939_spi_reset();
|
||||
uint32_t Ia = bl0939_read_reg(0x00);
|
||||
// return Ia * 1.218f / (float) ( 324004 * 1 );
|
||||
return Ia;
|
||||
}
|
||||
// T = 40ms
|
||||
int bl0939_get_current_B()
|
||||
{
|
||||
bl0939_spi_reset();
|
||||
uint32_t Ib = bl0939_read_reg(0x07);
|
||||
// return Ib * 1.218f / (float) ( 324004 * 1 );
|
||||
return Ib;
|
||||
}
|
||||
// T = 400ms
|
||||
int bl0939_get_voltage()
|
||||
{
|
||||
bl0939_spi_reset();
|
||||
uint32_t v = bl0939_read_reg(0x06);
|
||||
// return v * 1.218f * ( 2 + 2000 ) / (float) ( 79931 * 2 * 1000 );
|
||||
return v;
|
||||
}
|
||||
|
||||
/// @brief
|
||||
uint8_t bl0939_cmd[36] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x55, 0x00, 0, 0, 0, 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x55, 0x07, 0, 0, 0, 0,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x55, 0x06, 0, 0, 0, 0};
|
||||
|
||||
int check_sum_ch(uint8_t *buf, int offset)
|
||||
{
|
||||
uint8_t sum = ~(0x55 + bl0939_cmd[offset - 1] + buf[offset] + buf[offset + 1] + buf[offset + 2]);
|
||||
if (buf[offset + 3] == sum)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
uint32_t readUint24LE(uint8_t *buf, int offset)
|
||||
{
|
||||
return buf[offset] | buf[offset + 1] << 8 | buf[offset + 2] << 16;
|
||||
}
|
||||
uint32_t readUint24BE(uint8_t *buf, int offset)
|
||||
{
|
||||
return buf[offset] << 16 | buf[offset + 1] << 8 | buf[offset + 2];
|
||||
}
|
||||
|
||||
// __IO uint8_t bl0939_Transfer_done = 0;
|
||||
uint8_t bl0939_Transfer_done = 0;
|
||||
|
||||
void bl0939_init(void)
|
||||
{
|
||||
bl0939_reset();
|
||||
}
|
||||
|
||||
float ac_current_coef[3] = {
|
||||
1.218f / (324004.f * 0.225 * 1000 / 2000) * 100.f,
|
||||
1.218f / (324004.f * 0.23 * 1000 / 2000) * 100.f,
|
||||
1.218f / (79931.f * 0.002 * 500) * 100.f};
|
||||
uint8_t bl0939_rxbuf[2][36];
|
||||
int32_t ac_ad_values[3] = {0};
|
||||
int move_time = 0;
|
||||
int move_req = 0;
|
||||
extern uint16_t gWordVar[];
|
||||
int move_status = 0;
|
||||
|
||||
void BL0939_task()
|
||||
{
|
||||
int index = 0;
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(10);
|
||||
// ESP_LOGI(TAG, "BL0939_SPI_TransmitReceive before\n ");
|
||||
bl0939_Transfer_done = 1;
|
||||
|
||||
BL0939_SPI_TransmitReceive(bl0939_cmd, bl0939_rxbuf[index & 1], 36);
|
||||
if (!memcmp(bl0939_rxbuf[0], bl0939_rxbuf[1], sizeof(bl0939_rxbuf[0])))
|
||||
{
|
||||
index++;
|
||||
bl0939_Transfer_done = 0;
|
||||
// continue;
|
||||
}
|
||||
// ESP_LOGI(TAG, "BL0939_SPI_TransmitReceive after\n ");
|
||||
if (bl0939_Transfer_done)
|
||||
{
|
||||
int ch;
|
||||
// ESP_LOGI(TAG, "bl0939_Transfer_done \n ");
|
||||
bl0939_Transfer_done = 0;
|
||||
for (ch = 0; ch < 3; ch++)
|
||||
{
|
||||
if (check_sum_ch(bl0939_rxbuf[index & 1], 8 + ch * 12))
|
||||
{
|
||||
ac_ad_values[ch] = readUint24BE(bl0939_rxbuf[index & 1], 8 + ch * 12);
|
||||
// ESP_LOGI(TAG, "channel : %d ac_ad_values: %d\n ", ch, ac_ad_values[ch]);
|
||||
gWordVar[AC_CURRENT_REG_ADDR + ch] = ac_ad_values[ch] * ac_current_coef[ch];
|
||||
}
|
||||
// ac_ad_values[ch] = readUint24BE(bl0939_rxbuf,8+ch*12);
|
||||
// ESP_LOGI(TAG, "channel : %d ac_ad_values: %d\n ", ch, ac_ad_values[ch]);
|
||||
}
|
||||
if (pMoveCtx->status == 0)
|
||||
{ // 停止状态,等待启动
|
||||
int move_current_channel = depth_config->move_current_channel;
|
||||
if (move_current_channel > 2 || move_current_channel < 0)
|
||||
{
|
||||
move_current_channel = 2;
|
||||
}
|
||||
if (gWordVar[AC_CURRENT_REG_ADDR + move_current_channel] > depth_config->current_on_threshold)
|
||||
{
|
||||
if (++pMoveCtx->time_count > depth_config->move_on_duratino)
|
||||
{
|
||||
pMoveCtx->status = 1;
|
||||
pMoveCtx->time_count = 0;
|
||||
pMoveCtx->pile_inc_req = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pMoveCtx->status == 1)
|
||||
{
|
||||
int move_current_channel = depth_config->move_current_channel;
|
||||
if (move_current_channel > 2 || move_current_channel < 0)
|
||||
{
|
||||
move_current_channel = 2;
|
||||
}
|
||||
if (gWordVar[AC_CURRENT_REG_ADDR + 2] < depth_config->current_off_threshold)
|
||||
{
|
||||
if (++pMoveCtx->time_count > depth_config->move_off_duration)
|
||||
{
|
||||
pMoveCtx->status = 0;
|
||||
pMoveCtx->time_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BL0939_init(void)
|
||||
{
|
||||
SPI1_Init();
|
||||
bl0939_init();
|
||||
xTaskCreate(BL0939_task, "BL0939_task", 4096, NULL, 10, NULL);
|
||||
}
|
31
main/stm32/bl0939.h
Normal file
31
main/stm32/bl0939.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef BL0939_H__
|
||||
#define BL0939_H__
|
||||
|
||||
|
||||
|
||||
// #include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/spi_master.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
|
||||
|
||||
void bl0939_reset(void);
|
||||
int bl0939_get_current_A(void);
|
||||
int bl0939_get_current_B(void);
|
||||
int bl0939_get_voltage(void);
|
||||
|
||||
//DMA
|
||||
void bl0939_get_abv(uint8_t * buf);
|
||||
int bl0939_parse_abv(uint8_t * buf,unsigned int * data);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
156
main/stm32/capture.c
Normal file
156
main/stm32/capture.c
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "driver/mcpwm.h"
|
||||
|
||||
const static char *TAG = "capture";
|
||||
|
||||
typedef struct capture_event
|
||||
{
|
||||
int ch;
|
||||
uint32_t val;
|
||||
}capture_event_t;
|
||||
|
||||
|
||||
#define FLOW1_PIN_ECHO GPIO_NUM_9 //捕获GPIO端口
|
||||
#define FLOW2_PIN_ECHO GPIO_NUM_10 //捕获GPIO端口
|
||||
|
||||
|
||||
#define TRIGGER_THREAD_PRIORITY 5
|
||||
|
||||
typedef struct {
|
||||
uint32_t capture_signal;
|
||||
mcpwm_capture_signal_t sel_cap_signal;
|
||||
} capture;
|
||||
|
||||
static uint32_t cap_val_begin_of_flow1 = 0;
|
||||
static uint32_t cap_val_end_of_flow1 = 0;
|
||||
static uint32_t cap_val_begin_of_flow2 = 0;
|
||||
static uint32_t cap_val_end_of_flow2 = 0;
|
||||
|
||||
static xQueueHandle cap_queue;
|
||||
extern uint32_t rtc_clk_apb_freq;
|
||||
uint32_t volatile t15_ccr[2];
|
||||
uint16_t volatile t15_ccr_times[2];
|
||||
|
||||
static bool flow1_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
||||
void *arg) {
|
||||
//calculate the interval in the ISR,
|
||||
//so that the interval will be always correct even when cap_queue is not handled in time and overflow.
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
|
||||
cap_val_end_of_flow1 = edata->cap_value;
|
||||
capture_event_t cap_event = {.val = 0, .ch = 1};
|
||||
cap_event.val = cap_val_end_of_flow1 - cap_val_begin_of_flow1;
|
||||
t15_ccr_times[0] = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
t15_ccr[0]++;
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
void capture_flow1_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_1, FLOW1_PIN_ECHO));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pullup_en(FLOW1_PIN_ECHO));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = flow1_isr_handler, //绑定流量捕获中断处理函数
|
||||
.user_data = NULL
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP1, &conf));
|
||||
mcpwm_set_frequency(MCPWM_UNIT_1, MCPWM_TIMER_1, 1000000);
|
||||
int value = mcpwm_capture_signal_get_value(MCPWM_UNIT_1,MCPWM_SELECT_CAP1);
|
||||
ESP_LOGI(TAG, "capture_flow_init value=%d",value);
|
||||
}
|
||||
|
||||
static bool flow2_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
||||
void *arg) {
|
||||
//calculate the interval in the ISR,
|
||||
//so that the interval will be always correct even when cap_queue is not handled in time and overflow.
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
|
||||
cap_val_end_of_flow2 = edata->cap_value;
|
||||
capture_event_t cap_event = {.val = 0, .ch = 2};
|
||||
cap_event.val = cap_val_end_of_flow2 - cap_val_begin_of_flow2;
|
||||
t15_ccr_times[1] = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
t15_ccr[1]++;
|
||||
// send measurement back though queue
|
||||
// xQueueSendFromISR(cap_queue, &cap_event, &high_task_wakeup);
|
||||
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
void capture_flow2_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_2, FLOW2_PIN_ECHO));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pulldown_en(FLOW2_PIN_ECHO));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = flow2_isr_handler, //绑定流量捕获中断处理函数
|
||||
.user_data = NULL
|
||||
};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP2, &conf));
|
||||
mcpwm_set_frequency(MCPWM_UNIT_1, MCPWM_TIMER_2, 1000000);
|
||||
ESP_LOGI(TAG, "capture_flow_init");
|
||||
}
|
||||
|
||||
|
||||
// void capture_task(void)
|
||||
// {
|
||||
// while (true) {
|
||||
// capture_event_t cap_event = {.val = 0, .ch = 1};
|
||||
// uint32_t pulse_width_us = 0;
|
||||
// // block and wait for new measurement
|
||||
// // ESP_LOGI(TAG, "xQueueReceive started");
|
||||
// xQueueReceive(cap_queue, &cap_event, portMAX_DELAY);
|
||||
// // ESP_LOGI(TAG, "xQueueReceive after");
|
||||
// // ESP_LOGI(TAG, " cap_event.val: %d, cap_event.ch : %d", cap_event.val, cap_event.ch);
|
||||
// switch (cap_event.ch)
|
||||
// {
|
||||
// case 1: //flow1 capture
|
||||
// pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
|
||||
// ESP_LOGI(TAG, " (flow1 capture) Pulse width: %uus", pulse_width_us);
|
||||
// break;
|
||||
// case 2: //flow2 capture
|
||||
// pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
// ESP_LOGI(TAG, "(flow2 capture) Pulse width: %uus", pulse_width_us);
|
||||
// break;
|
||||
// default: ESP_LOGI(TAG, " default\n");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// void capture_depth_init();
|
||||
// void pcnt_rotary_encoder_init(void);
|
||||
void capture_init(void)
|
||||
{
|
||||
// cap_queue = xQueueCreate(3, sizeof(capture_event_t));
|
||||
// if (cap_queue == NULL) {
|
||||
// ESP_LOGE(TAG, "failed to alloc cap_queue");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// capture_depth_init();
|
||||
capture_flow1_init();
|
||||
capture_flow2_init();
|
||||
// start gcapture_task
|
||||
// xTaskCreate(capture_task, "capture_task", 4096, NULL, TRIGGER_THREAD_PRIORITY, NULL);
|
||||
// ESP_LOGI(TAG, "capture_task started");
|
||||
// pcnt_rotary_encoder_init();
|
||||
}
|
105
main/stm32/comm.c
Normal file
105
main/stm32/comm.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include "stdlib.h"
|
||||
#include "utils.h"
|
||||
#include "fram.h"
|
||||
#include "ModbusS.h"
|
||||
#include "ads1220.h"
|
||||
// #include "SEGGER_RTT.h"
|
||||
#include "ModbusM.h"
|
||||
|
||||
uint32_t TickDiff(uint32_t comptime);
|
||||
extern void modbus_master_poll(int n);
|
||||
extern int modbus_master_on_revice(int ch, uint8_t *rxbuf, int length);
|
||||
|
||||
extern uint8_t uart1_txbuf[];
|
||||
extern uint8_t uart1_rxbuf[];
|
||||
|
||||
extern uint8_t uart2_txbuf[];
|
||||
extern uint8_t uart2_rxbuf[];
|
||||
|
||||
extern int uart1_rx_start(void);
|
||||
extern int uart1_rx_check(void);
|
||||
extern int uart1_tx_start(uint8_t *data, int length);
|
||||
|
||||
|
||||
extern int uart2_rx_start(void);
|
||||
extern int uart2_rx_check(void);
|
||||
extern int uart2_tx_start(uint8_t *data, int length);
|
||||
|
||||
void RS485_init();
|
||||
void print_init();
|
||||
|
||||
extern uint8_t led_toggle_count;
|
||||
|
||||
|
||||
|
||||
void comm_poll(void)
|
||||
{
|
||||
|
||||
static uint32_t modbus_master_tick = 0;
|
||||
static uint32_t tick_100ms = 0;
|
||||
static int uart1_timeout = 0;
|
||||
static int uart2_timeout = 0;
|
||||
int rxlen,txlen;
|
||||
// if((rxlen = uart1_rx_check()) > 0){
|
||||
// txlen = ModbusSlaveProcess(uart1_txbuf,uart1_rxbuf,rxlen,1);
|
||||
// if(txlen > 0)
|
||||
// {
|
||||
// HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
|
||||
// uart1_tx_start(uart1_txbuf,txlen);
|
||||
// }
|
||||
// else{
|
||||
// uart1_rx_start();
|
||||
// }
|
||||
// }
|
||||
if((rxlen = uart2_rx_check()) > 0){
|
||||
|
||||
txlen = ModbusSlaveProcess(uart2_txbuf,uart2_rxbuf,rxlen,1);
|
||||
if(txlen > 0)
|
||||
{
|
||||
uart2_tx_start(uart2_txbuf,txlen);
|
||||
}
|
||||
else{
|
||||
uart2_rx_start();
|
||||
}
|
||||
led_toggle_count = 0;
|
||||
uart1_timeout = 0;
|
||||
}
|
||||
if(TickDiff(tick_100ms) > 100)
|
||||
{
|
||||
tick_100ms = xTaskGetTickCount();
|
||||
if(++uart1_timeout > 100){
|
||||
uart1_timeout = 0;
|
||||
// HAL_UART_MspDeInit(&huart2);
|
||||
// MX_USART2_UART_Init();
|
||||
uart2_rx_start();
|
||||
}
|
||||
if(++uart2_timeout > 1000){
|
||||
uart2_timeout = 0;
|
||||
// HAL_UART_MspDeInit(&huart1);
|
||||
// MX_USART1_UART_Init();
|
||||
}
|
||||
}
|
||||
if(TickDiff(modbus_master_tick) > 10)
|
||||
{
|
||||
modbus_master_tick = xTaskGetTickCount();
|
||||
modbus_master_poll(0);
|
||||
}
|
||||
if((rxlen = uart1_rx_check()) > 0){ // 做一个uart1_rx_check 读串口
|
||||
modbus_master_on_revice(0,uart1_rxbuf,rxlen);
|
||||
uart2_timeout = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void comm_init(void)
|
||||
{
|
||||
// MX_USART1_UART_Init();
|
||||
// MX_USART2_UART_Init();
|
||||
RS485_init();
|
||||
print_init();
|
||||
ModbusM_init();
|
||||
uart2_rx_start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
150
main/stm32/config.c
Normal file
150
main/stm32/config.c
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "fram.h"
|
||||
#include "utils.h"
|
||||
#include "modbuss.h"
|
||||
#include "stdint.h"
|
||||
#include "esp_log.h"
|
||||
// #include "flow.h"
|
||||
// #include "depth.h"
|
||||
// config_data_t * config_para = (config_data_t*)&gWordVar[256];
|
||||
// extern real_t * real;
|
||||
|
||||
static const char *TAG = "config";
|
||||
|
||||
extern cal_4_20ma_t *cal_4_20ma;
|
||||
extern flow_config_t *flow_config;
|
||||
extern depth_config_t *depth_config;
|
||||
|
||||
extern float ac_current_coef[3];
|
||||
// 三标一号机
|
||||
const cal_4_20ma_t default_cal_4_20ma = {0, {{12740, 63845}, {12760, 63953}}};
|
||||
const flow_config_t default_flow_cfg = {0, 1, {0, 0}, {{0, 10000}, {0, 10000}}, {6944, 6944}}; // 4~20MA 输入6m/H 100.00L/min
|
||||
// const flow_config_t default_flow_cfg = {0,1,{60,60},{{0,20000},{0,20000}},{6944,6944}}; //脉冲输入 12m/H
|
||||
// const depth_config_t default_depth_cfg = {0, 2,0, 1000, 32, -100, 12000, 100, -100, 1000,500, 500, 100, 150, 150}; // 方向脉冲编码器 10线2倍频
|
||||
const depth_config_t default_depth_cfg = {
|
||||
.magic = 0,
|
||||
.input_type = 0,
|
||||
.port = 1,
|
||||
.N = 1000,
|
||||
.M = 640,
|
||||
.min_depth = -100,
|
||||
.max_depth = 12000,
|
||||
.sample_depth = 100,
|
||||
.depth_offset = -100,
|
||||
.min_valid_depth = 1000,
|
||||
.inc_pile_depth = 5000,
|
||||
.current_on_threshold = 500,
|
||||
.current_off_threshold = 100,
|
||||
.move_on_duratino = 150,
|
||||
.move_off_duration = 150,
|
||||
.move_current_channel = 2,
|
||||
}; // 方向脉冲编码器 10线2倍频
|
||||
|
||||
// const depth_config_t default_depth_cfg = {0,3,0,3800,-200,16000,100,-200}; //200线开漏型正交
|
||||
// const depth_config_t default_depth_cfg = {0,1,0,76000,-200,16000,100,-200};
|
||||
|
||||
#define MAGIC 30627
|
||||
#define EE_CAL_4_20MA_ADDR 16
|
||||
#define EE_FLOW_CFG_ADDR (EE_CAL_4_20MA_ADDR + sizeof(default_cal_4_20ma))
|
||||
#define EE_DEPTH_CFG_ADDR (EE_FLOW_CFG_ADDR + sizeof(default_flow_cfg))
|
||||
|
||||
extern uint16_t last_pile_id = 0;
|
||||
|
||||
extern void init_comm(void);
|
||||
|
||||
// void sys_init(void)
|
||||
// {
|
||||
// // HAL_Delay(100);
|
||||
// // GetCompileDateTime(&gWordVar[0]);
|
||||
// // flash_load();
|
||||
// // modbus_addr = config_para->modbus_addr;
|
||||
// // sliding_window_filter_init(&sliding_window_a,real->data_long,200);
|
||||
// // HAL_TIM_Base_Start(&htim6);//ms<6D><73>ʱ<EFBFBD><CAB1>
|
||||
// // HAL_TIM_Base_Start_IT(&htim17);//us<75><73>ʱ<EFBFBD><CAB1>
|
||||
// //// HAL_TIM_Encoder_Start_IT(&htim1,TIM_CHANNEL_ALL);//enc
|
||||
// // HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);//enc
|
||||
// // HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_1);//ll
|
||||
// // HAL_TIM_IC_Start_IT(&htim1,TIM_CHANNEL_2);//ll
|
||||
// // HAL_TIM_IC_Start_IT(&htim15,TIM_CHANNEL_1);//ll
|
||||
// // HAL_TIM_IC_Start_IT(&htim15,TIM_CHANNEL_2);//ll
|
||||
// // HAL_UART_Receive_IT(&huart1,&temp_rx_data,1);
|
||||
// // init_comm();
|
||||
// // if(config_para->traffic_mode == MA_4_20)
|
||||
// // {
|
||||
// // ADS1220_Init();
|
||||
// // }
|
||||
// // HAL_GPIO_WritePin(GPS_PWR_EN_GPIO_Port, GPS_PWR_EN_Pin, GPIO_PIN_SET);
|
||||
// // HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin,0);
|
||||
// // HAL_Delay(500);
|
||||
// }
|
||||
void config_load(void)
|
||||
{
|
||||
uint16_t temp[2];
|
||||
fram_read(0, &temp, sizeof(temp));
|
||||
{
|
||||
if (temp[0] == MAGIC)
|
||||
{
|
||||
last_pile_id = temp[1];
|
||||
}
|
||||
}
|
||||
fram_read(EE_CAL_4_20MA_ADDR, cal_4_20ma, sizeof(default_cal_4_20ma));
|
||||
if (cal_4_20ma->magic != MAGIC)
|
||||
{
|
||||
ESP_LOGI(TAG, "fram_read cal_4_20ma failed, use default value");
|
||||
memcpy(cal_4_20ma, &default_cal_4_20ma, sizeof(default_cal_4_20ma));
|
||||
}
|
||||
fram_read(EE_FLOW_CFG_ADDR, flow_config, sizeof(default_flow_cfg));
|
||||
if (flow_config->magic != MAGIC)
|
||||
{
|
||||
ESP_LOGW(TAG, "fram_read flow_config failed, use default value");
|
||||
memcpy(flow_config, &default_flow_cfg, sizeof(default_flow_cfg));
|
||||
}
|
||||
|
||||
fram_read(EE_DEPTH_CFG_ADDR, depth_config, sizeof(default_depth_cfg));
|
||||
if (depth_config->magic != MAGIC)
|
||||
{
|
||||
ESP_LOGW(TAG, "fram_read depth_config failed, use default value");
|
||||
memcpy(depth_config, &default_depth_cfg, sizeof(default_depth_cfg));
|
||||
}
|
||||
fram_read(EE_DEPTH_CFG_ADDR, depth_config, sizeof(default_depth_cfg));
|
||||
if (depth_config->magic != MAGIC)
|
||||
{
|
||||
ESP_LOGW(TAG, "fram_read depth_config failed, use default value");
|
||||
memcpy(depth_config, &default_depth_cfg, sizeof(default_depth_cfg));
|
||||
}
|
||||
}
|
||||
|
||||
void restore_default(void)
|
||||
{
|
||||
memcpy(cal_4_20ma, &default_cal_4_20ma, sizeof(default_cal_4_20ma));
|
||||
memcpy(flow_config, &default_flow_cfg, sizeof(default_flow_cfg));
|
||||
memcpy(depth_config, &default_depth_cfg, sizeof(default_depth_cfg));
|
||||
fram_write(EE_CAL_4_20MA_ADDR, cal_4_20ma, sizeof(default_cal_4_20ma));
|
||||
fram_write(EE_FLOW_CFG_ADDR, flow_config, sizeof(default_flow_cfg));
|
||||
fram_write(EE_DEPTH_CFG_ADDR, depth_config, sizeof(default_depth_cfg));
|
||||
}
|
||||
|
||||
void save_cal_4_20ma(void)
|
||||
{
|
||||
cal_4_20ma->magic = MAGIC;
|
||||
cal_4_20ma->magic = fram_write(EE_CAL_4_20MA_ADDR, cal_4_20ma, sizeof(default_cal_4_20ma));
|
||||
}
|
||||
|
||||
void save_flow_cfg(void)
|
||||
{
|
||||
flow_config->magic = MAGIC;
|
||||
flow_config->magic = fram_write(EE_FLOW_CFG_ADDR, flow_config, sizeof(default_flow_cfg));
|
||||
}
|
||||
|
||||
void save_depth_cfg(void)
|
||||
{
|
||||
depth_config->magic = MAGIC;
|
||||
depth_config->magic = fram_write(EE_DEPTH_CFG_ADDR, depth_config, sizeof(default_depth_cfg));
|
||||
}
|
||||
|
||||
void save_pile_id(void)
|
||||
{
|
||||
uint16_t temp[2] = {MAGIC, last_pile_id};
|
||||
fram_write(0, &temp, sizeof(temp));
|
||||
}
|
99
main/stm32/config.h
Normal file
99
main/stm32/config.h
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef SYS_H__
|
||||
#define SYS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t magic;
|
||||
struct _ch
|
||||
{
|
||||
uint16_t ad_4ma;
|
||||
uint16_t ad_20ma;
|
||||
} ch[2];
|
||||
} cal_4_20ma_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t flow_min;
|
||||
int16_t flow_max;
|
||||
} ad_flow_cal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t magic;
|
||||
uint16_t input_type; // 1 : 4~20ma 2: 0~3.6K
|
||||
int16_t min_flow[2]; // 小流量切除
|
||||
ad_flow_cal_t ad_cal[2];
|
||||
uint16_t pulse_coef[2];
|
||||
uint16_t rsv[6];
|
||||
} flow_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t magic;
|
||||
uint8_t input_type; // 0:正交 1:正交反向 2:方向脉冲 3:方向脉冲反向
|
||||
uint8_t port; // 编码器端口
|
||||
uint16_t N; //编码器系数分子
|
||||
uint16_t M; //编码器系数分母
|
||||
// int pluse_coef; // 脉冲系数0.001mm
|
||||
int16_t min_depth; // 最小深度 mm
|
||||
int16_t max_depth; // 最大深度 mm
|
||||
int16_t sample_depth; // 采样深度 mm
|
||||
int16_t depth_offset; // 默认深度偏移
|
||||
int16_t min_valid_depth; // 最小有效深度
|
||||
int16_t inc_pile_depth; // 允许换桩深度
|
||||
uint16_t current_on_threshold; // 行走电机开启电流
|
||||
uint16_t current_off_threshold; // 行走电机关闭电流
|
||||
uint16_t move_on_duratino; // 持续时间
|
||||
uint16_t move_off_duration; // 持续时间
|
||||
uint16_t move_current_channel; //行走电流通道
|
||||
} depth_config_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t flow_;
|
||||
int16_t flow;
|
||||
int32_t total_flow;
|
||||
uint32_t update_time;
|
||||
} flow_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t status; // 0:未开始 1:开始 2:结束
|
||||
uint16_t time_count; //持续时间
|
||||
uint16_t pile_inc_req;
|
||||
} move_t;
|
||||
|
||||
|
||||
extern depth_config_t *depth_config;
|
||||
|
||||
#define FLOW_REG_ADDR 0
|
||||
#define DEPTH_REG_ADDR 12
|
||||
#define AC_CURRENT_REG_ADDR 24
|
||||
#define MOVE_REG_ADDR 27
|
||||
#define TILT_SENSER_ADDR 30
|
||||
#define RECORD_REG_ADDR 32
|
||||
|
||||
#define CAL_4_20MA_ADDR 384
|
||||
#define FLOW_CONFIG_ADDR (CAL_4_20MA_ADDR + (sizeof(cal_4_20ma_t) + 15) / 16 * 8)
|
||||
#define DEPTH_CONFIG_ADDR (FLOW_CONFIG_ADDR + (sizeof(flow_config_t) + 15) / 16 * 8)
|
||||
|
||||
#define AD_RAW_REG_ADDR 444
|
||||
#define LAST_PILE_ID_ADDR 509
|
||||
#define DEPTH_RESET_ADDR 510
|
||||
#define REBOOT_REW_ADDR 511
|
||||
void config_load(void);
|
||||
void save_cal_4_20ma(void);
|
||||
void save_flow_cfg(void);
|
||||
void save_depth_cfg(void);
|
||||
void restore_default(void);
|
||||
|
||||
#endif
|
507
main/stm32/depth.c
Normal file
507
main/stm32/depth.c
Normal file
@ -0,0 +1,507 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "stdlib.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "ads1220.h"
|
||||
#include "fram.h"
|
||||
#include "ModbusM.h"
|
||||
#include "ModbusS.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "config.h"
|
||||
|
||||
static const char *TAG = "depth";
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t capture_signal;
|
||||
mcpwm_capture_signal_t sel_cap_signal;
|
||||
} capture;
|
||||
|
||||
typedef struct capture_event
|
||||
{
|
||||
int ch;
|
||||
uint32_t val;
|
||||
} capture_event_t;
|
||||
|
||||
// #define DEPTH_PIN_CLK GPIO_NUM_36 // 捕获GPIO端口
|
||||
// #define GPIO_PCNT_PIN_1 36 // Set GPIO 18 as phaseA/C1
|
||||
// #define GPIO_PCNT_PIN_2 35 // Set GPIO 19 as phaseB/C2
|
||||
// #define DEPTH_PIN_PULSE 36 //深度脉冲GPIO端口
|
||||
// #define DEPTH_PIN_CTRL 35 //深度控制GPIO端口
|
||||
|
||||
#define FLOW_SYNC_PIN 39 // 捕获GPIO端口
|
||||
|
||||
#define DEPTH_PIN_PULSE 9 // 深度脉冲GPIO端口
|
||||
#define DEPTH_PIN_CTRL 10 // 深度控制GPIO端口
|
||||
#define DEPTH_PIN_ENC_A 36 // 深度脉冲GPIO端口
|
||||
#define DEPTH_PIN_ENC_B 35 // 深度控制GPIO端口
|
||||
|
||||
// #define DEPTH_PIN_ENC_A 36 // 深度脉冲GPIO端口
|
||||
// #define DEPTH_PIN_ENC_B 35 // 深度控制GPIO端口
|
||||
|
||||
void add_recod_item(void);
|
||||
|
||||
extern int get_total_flow_by_time(int ch, uint32_t time);
|
||||
extern void zero_totalflow(int ch);
|
||||
|
||||
extern void reset_depth(void);
|
||||
|
||||
void capture_depth_init();
|
||||
extern flow_t *pflow;
|
||||
extern uint16_t last_pile_id;
|
||||
uint32_t enc1_update_time;
|
||||
uint32_t _enc1_update_time;
|
||||
int32_t enc1_value;
|
||||
|
||||
uint32_t enc2_update_time;
|
||||
uint32_t _enc2_update_time;
|
||||
int32_t enc2_value;
|
||||
|
||||
extern rotary_encoder_t *encoder;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t max_depth;
|
||||
uint16_t pile_id;
|
||||
uint16_t count;
|
||||
uint16_t work_time;
|
||||
struct _item
|
||||
{
|
||||
int16_t speed;
|
||||
int16_t depth;
|
||||
int16_t flow[2];
|
||||
uint32_t total_flow[2];
|
||||
int16_t tilt_x;
|
||||
int16_t tilt_y;
|
||||
uint16_t current1;
|
||||
uint16_t current2;
|
||||
} item[10];
|
||||
} record_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int16_t up_down; // 12
|
||||
int16_t speed; // 13
|
||||
int16_t depth; // 14
|
||||
uint16_t sample_count; // 15
|
||||
uint16_t depth_flow[2]; // 16~17
|
||||
uint32_t last_total_flow[2]; // 18~21
|
||||
int16_t depth_offset; // 22
|
||||
// uint32_t update_time;
|
||||
// int16_t tilt_x;
|
||||
// int16_t tilt_y;
|
||||
// uint16_t current1;
|
||||
// uint16_t current2;
|
||||
// uint16_t current3;
|
||||
} depth_t;
|
||||
|
||||
record_t *record = (record_t *)&gWordVar[RECORD_REG_ADDR];
|
||||
depth_t *depth_data = (depth_t *)&gWordVar[DEPTH_REG_ADDR];
|
||||
|
||||
move_t *pMoveCtx = (move_t *)&gWordVar[MOVE_REG_ADDR];
|
||||
|
||||
depth_config_t *depth_config = (depth_config_t *)&gWordVar[DEPTH_CONFIG_ADDR];
|
||||
|
||||
rotary_encoder_t *encoder = NULL; // 编码器测量深度参数
|
||||
|
||||
static uint32_t cap_val_begin_of_depth = 0;
|
||||
static uint32_t cap_val_end_of_depth = 0;
|
||||
extern uint32_t rtc_clk_apb_freq;
|
||||
/**
|
||||
* @brief this is an ISR callback, we take action according to the captured edge
|
||||
*/
|
||||
static bool depth_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
||||
void *arg)
|
||||
{
|
||||
|
||||
// 双边沿触发中断,只有一个边缘会更新值,所以只有在值发生变化是才更新时间
|
||||
int value = encoder->get_counter_value(encoder);
|
||||
if (value != enc1_value)
|
||||
{
|
||||
enc1_value = value;
|
||||
enc1_update_time = edata->cap_value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void capture_depth_init()
|
||||
{
|
||||
int pulse_pin;
|
||||
if (depth_config->port)
|
||||
{
|
||||
pulse_pin = DEPTH_PIN_ENC_A;
|
||||
}
|
||||
else
|
||||
{
|
||||
pulse_pin = DEPTH_PIN_PULSE;
|
||||
}
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM_CAP_0, pulse_pin));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pullup_en(pulse_pin));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = depth_isr_handler, // 绑定深度中断处理函数
|
||||
.user_data = NULL};
|
||||
if (depth_config->input_type > 1)
|
||||
{
|
||||
conf.cap_edge = MCPWM_BOTH_EDGE;
|
||||
}
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, &conf));
|
||||
ESP_LOGI(TAG, "capture_depth_init");
|
||||
}
|
||||
|
||||
void pcnt_rotary_encoder_init(void)
|
||||
{
|
||||
// Rotary encoder underlying device is represented by a PCNT unit in this example
|
||||
uint32_t pcnt_unit = 0;
|
||||
int pulse_pin;
|
||||
int ctrl_pin;
|
||||
if (depth_config->port)
|
||||
{
|
||||
pulse_pin = DEPTH_PIN_ENC_A;
|
||||
ctrl_pin = DEPTH_PIN_ENC_B;
|
||||
}
|
||||
else
|
||||
{
|
||||
pulse_pin = DEPTH_PIN_PULSE;
|
||||
ctrl_pin = DEPTH_PIN_CTRL;
|
||||
}
|
||||
// Create rotary encoder instance
|
||||
rotary_encoder_config_t config = ROTARY_ENCODER_DEFAULT_CONFIG((rotary_encoder_dev_t)pcnt_unit, pulse_pin, ctrl_pin);
|
||||
config.flags = depth_config->input_type;
|
||||
ESP_ERROR_CHECK(rotary_encoder_new_ec11(&config, &encoder));
|
||||
// Filter out glitch (1us)
|
||||
ESP_ERROR_CHECK(encoder->set_glitch_filter(encoder, 10));
|
||||
// Start encoder
|
||||
ESP_ERROR_CHECK(encoder->start(encoder));
|
||||
}
|
||||
|
||||
void depth_init(void)
|
||||
{
|
||||
// if (depth_config->input_type == 1)
|
||||
// { // 电压型 方向+脉冲信号 使用比较器通道,IO口中断方式采集
|
||||
|
||||
// // GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
// // /*Configure GPIO pin : PtPin */
|
||||
// // GPIO_InitStruct.Pin = ROLLER_DIR_Pin;
|
||||
// // GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
// // GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
// // HAL_GPIO_Init(ROLLER_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
// // /*Configure GPIO pin : PtPin */
|
||||
// // GPIO_InitStruct.Pin = ROLLER_CLK_Pin;
|
||||
// // GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
|
||||
// // GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
// // HAL_GPIO_Init(ROLLER_GPIO_Port, &GPIO_InitStruct);
|
||||
// }
|
||||
// else if (depth_config->input_type == 2)
|
||||
// { // 电压型 正交编码器 使用比较器通道,TIM1编码器通道采集
|
||||
// MX_TIM1_Init();
|
||||
// pcnt_rotary_encoder_init(); // 编码器初始化
|
||||
// capture_depth_init();
|
||||
// HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
|
||||
// }
|
||||
// else if (depth_config->input_type == 3)
|
||||
// { // 开漏输出 正交编码器 使用光耦输入通道,TIM3编码器通道采集
|
||||
// // MX_TIM3_Init();
|
||||
// // HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);
|
||||
// }
|
||||
depth_data->depth_offset = -depth_config->depth_offset;
|
||||
depth_data->up_down = 1; // 默认工作
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
REST = -1,
|
||||
STOP = 0,
|
||||
DOWN = 1,
|
||||
UP = 2,
|
||||
};
|
||||
|
||||
int last_enc_value = 0;
|
||||
uint32_t _enc_update_time;
|
||||
uint32_t enc_update_time;
|
||||
int last_sample_depth = 0;
|
||||
int last_flow[2] = {0};
|
||||
int16_t prev_depth = 0;
|
||||
uint32_t prev_update_time = 0;
|
||||
int16_t target_sample_depth = 0;
|
||||
|
||||
// 正交编码器的深度 : encoder->get_counter_value(encoder)
|
||||
|
||||
int abs_sub(uint32_t enc_update_time, uint32_t _enc_update_time)
|
||||
{
|
||||
if (enc_update_time >= _enc_update_time)
|
||||
{
|
||||
return enc_update_time - _enc_update_time;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (0xffffffff - _enc_update_time + enc_update_time + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void depth_task(void)
|
||||
{
|
||||
// int enc_value;
|
||||
int time_diff = 0;
|
||||
int speed_timeout = 0;
|
||||
int last_speed_enc_value = 0; // 上次速度计算的编码器值
|
||||
int speed_enc_update_time = 0; // 上次速度计算的编码器值
|
||||
int speed_calc_count = 0;
|
||||
int enc_value = 0;
|
||||
int count = 0;
|
||||
depth_data->depth_offset = -depth_config->depth_offset;
|
||||
depth_data->up_down = 1; // 默认工作
|
||||
record->pile_id = ++last_pile_id;
|
||||
gWordVar[LAST_PILE_ID_ADDR] = last_pile_id;
|
||||
while (1)
|
||||
{
|
||||
if (_enc1_update_time != enc1_update_time)
|
||||
{
|
||||
// int enc_update_time = enc1_update_time;
|
||||
enc_update_time = enc1_update_time;
|
||||
enc_value = enc1_value;
|
||||
time_diff = abs_sub(enc_update_time, _enc1_update_time);
|
||||
_enc1_update_time = enc_update_time;
|
||||
}
|
||||
// }
|
||||
if (time_diff != 0)
|
||||
{
|
||||
int16_t depth = enc_value * depth_config->N / depth_config->M; // 1mm
|
||||
depth_data->depth = depth - depth_data->depth_offset;
|
||||
if (depth_data->depth > depth_config->max_depth)
|
||||
{
|
||||
depth_data->depth_offset = depth - depth_config->max_depth;
|
||||
depth_data->depth = depth_config->max_depth;
|
||||
}
|
||||
else if (depth_data->depth < depth_config->min_depth)
|
||||
{
|
||||
depth_data->depth_offset = depth - depth_config->min_depth;
|
||||
depth_data->depth = depth_config->min_depth;
|
||||
}
|
||||
if (depth_data->depth > record->max_depth)
|
||||
{
|
||||
record->max_depth = depth_data->depth;
|
||||
}
|
||||
if (speed_calc_count++ > 50) // 500ms计算一次速度
|
||||
{
|
||||
speed_calc_count = 0;
|
||||
int speed_time_diff = abs_sub(enc_update_time, speed_enc_update_time);
|
||||
int time_diff_us = speed_time_diff / (APB_CLK_FREQ / 1000000);
|
||||
if (time_diff_us > 0 && time_diff_us < 5000000)
|
||||
{
|
||||
ESP_LOGI(TAG, "time_diff_us:%d,dist_diff=%d", time_diff_us, enc_value - last_speed_enc_value);
|
||||
// speed = dist_diff / speed_time_diff speed 单位mm/min dist_diff 单位mm speed_time_diff 单位us
|
||||
depth_data->speed = (enc_value - last_speed_enc_value) * depth_config->N / depth_config->M * 600000ll / time_diff_us;
|
||||
speed_timeout = 0;
|
||||
speed_enc_update_time = enc_update_time;
|
||||
last_speed_enc_value = enc_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++speed_timeout > 10)
|
||||
{
|
||||
depth_data->speed = 0;
|
||||
speed_timeout = 0;
|
||||
speed_enc_update_time = enc_update_time;
|
||||
last_speed_enc_value = enc_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (depth_data->up_down > STOP)
|
||||
{
|
||||
if (enc_value > last_enc_value)
|
||||
{ // 下钻,深度增加
|
||||
if (depth_data->up_down != 1)
|
||||
{ // 方向改变
|
||||
depth_data->up_down = 1;
|
||||
target_sample_depth = (depth_data->depth / depth_config->sample_depth) * depth_config->sample_depth;
|
||||
if (abs(depth_data->depth - target_sample_depth) < depth_config->sample_depth / 2)
|
||||
{ // 小于半个采样长度的合并到下一个采样点
|
||||
target_sample_depth += depth_config->sample_depth;
|
||||
}
|
||||
}
|
||||
if (depth_data->depth >= target_sample_depth)
|
||||
{ // 到达或超过目标采样点
|
||||
// 由于编码器精度问题不能确保数据在采样点上,需要通过插值计算采样点
|
||||
// 当使用10线编码器时每个脉冲深度达6.25cm,当采样间隔为10cm时抖动值太大
|
||||
if ((prev_depth - depth_data->depth) != 0)
|
||||
{
|
||||
int i;
|
||||
uint32_t time = (target_sample_depth - prev_depth) * (enc_update_time - prev_update_time) / (depth_data->depth - prev_depth) + prev_update_time;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
// int total_flow = get_total_flow_by_time(i, time);
|
||||
int total_flow = get_total_flow_by_time(i, pflow[i].update_time);
|
||||
int flow = total_flow - depth_data->last_total_flow[i];
|
||||
if (flow < 0)
|
||||
{
|
||||
flow = 0;
|
||||
}
|
||||
depth_data->depth_flow[i] = flow;
|
||||
depth_data->last_total_flow[i] = total_flow;
|
||||
}
|
||||
depth_data->sample_count++;
|
||||
target_sample_depth += depth_config->sample_depth;
|
||||
add_recod_item();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (enc_value < last_enc_value)
|
||||
{
|
||||
if (depth_data->up_down != 2)
|
||||
{ // 方向改变
|
||||
depth_data->up_down = 2;
|
||||
// target_sample_depth -= depth_config->sample_depth;
|
||||
target_sample_depth = (depth_data->depth / depth_config->sample_depth - 1) * depth_config->sample_depth;
|
||||
if (abs(depth_data->depth - target_sample_depth) < depth_config->sample_depth / 2)
|
||||
{ // 小于半个采样长度的合并到下一个采样点
|
||||
target_sample_depth -= depth_config->sample_depth;
|
||||
}
|
||||
}
|
||||
if (depth_data->depth <= target_sample_depth)
|
||||
{
|
||||
// 由于编码器精度问题不能确保数据在采样点上,需要通过插值计算采样点
|
||||
// 当使用10线编码器时每个脉冲深度达7.6cm,当采样间隔为10cm时抖动值太大
|
||||
if ((prev_depth - depth_data->depth) != 0)
|
||||
{
|
||||
int i;
|
||||
uint32_t time = (prev_depth - target_sample_depth) * (enc_update_time - prev_update_time) / (prev_depth - depth_data->depth) + prev_update_time;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
// int total_flow = get_total_flow_by_time(i, time);
|
||||
int total_flow = get_total_flow_by_time(i, pflow[i].update_time);
|
||||
int flow = total_flow - depth_data->last_total_flow[i];
|
||||
if (flow < 0)
|
||||
{
|
||||
flow = 0;
|
||||
}
|
||||
depth_data->depth_flow[i] = flow;
|
||||
depth_data->last_total_flow[i] = total_flow;
|
||||
}
|
||||
depth_data->sample_count++;
|
||||
add_recod_item();
|
||||
target_sample_depth -= depth_config->sample_depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// depth_data->up_down = 0;
|
||||
}
|
||||
if (depth_data->depth < depth_config->inc_pile_depth) // 小于指定深度时才允许行走清零
|
||||
{
|
||||
if (pMoveCtx->pile_inc_req == 1)
|
||||
{
|
||||
pMoveCtx->pile_inc_req = 0;
|
||||
reset_depth();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pMoveCtx->pile_inc_req == 1)
|
||||
{
|
||||
pMoveCtx->pile_inc_req = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_depth = depth_data->depth;
|
||||
prev_update_time = enc_update_time;
|
||||
last_enc_value = enc_value;
|
||||
}
|
||||
|
||||
// if (++count > 100)
|
||||
// {
|
||||
// count = 0;
|
||||
// ESP_LOGI(TAG, "encoder:%d", encoder->get_counter_value(encoder));
|
||||
// }
|
||||
vTaskDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
void add_recod_item(void)
|
||||
{
|
||||
record->count = depth_data->sample_count;
|
||||
memmove(&record->item[1], &record->item[0], sizeof(record->item[0]) * 9);
|
||||
record->item[0].flow[0] = depth_data->depth_flow[0];
|
||||
record->item[0].flow[1] = depth_data->depth_flow[1];
|
||||
record->item[0].total_flow[0] = depth_data->last_total_flow[0];
|
||||
record->item[0].total_flow[1] = depth_data->last_total_flow[1];
|
||||
if (depth_config->move_current_channel == 2) // 1
|
||||
{
|
||||
record->item[0].current1 = gWordVar[AC_CURRENT_REG_ADDR];
|
||||
record->item[0].current2 = gWordVar[AC_CURRENT_REG_ADDR + 1];
|
||||
}
|
||||
else if (depth_config->move_current_channel == 1)
|
||||
{
|
||||
record->item[0].current1 = gWordVar[AC_CURRENT_REG_ADDR];
|
||||
record->item[0].current2 = gWordVar[AC_CURRENT_REG_ADDR + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
record->item[0].current1 = gWordVar[AC_CURRENT_REG_ADDR + 1];
|
||||
record->item[0].current2 = gWordVar[AC_CURRENT_REG_ADDR + 2];
|
||||
}
|
||||
|
||||
record->item[0].tilt_x = (short)gWordVar[TILT_SENSER_ADDR];
|
||||
record->item[0].tilt_y = (short)gWordVar[TILT_SENSER_ADDR + 1];
|
||||
record->item[0].speed = depth_data->speed;
|
||||
record->item[0].depth = depth_data->depth;
|
||||
}
|
||||
extern int zero_totalflow_req;
|
||||
extern void save_pile_id(void);
|
||||
void reset_depth(void)
|
||||
{
|
||||
uint16_t pile_id;
|
||||
last_sample_depth = 0;
|
||||
last_flow[0] = 0;
|
||||
last_flow[1] = 0;
|
||||
prev_depth = 0;
|
||||
prev_update_time = 0;
|
||||
target_sample_depth = 0;
|
||||
zero_totalflow_req = 1;
|
||||
if (record->count > 0)
|
||||
{
|
||||
record->count = 0;
|
||||
memset(record->item, 0, sizeof(record->item));
|
||||
}
|
||||
memset(depth_data, 0, sizeof(*depth_data));
|
||||
if (record->max_depth >= depth_config->min_valid_depth) // 上一个桩有一定深度数据
|
||||
{
|
||||
save_pile_id();
|
||||
last_pile_id++;
|
||||
gWordVar[LAST_PILE_ID_ADDR] = last_pile_id;
|
||||
}
|
||||
memset(record, 0, sizeof(*record));
|
||||
record->pile_id = last_pile_id;
|
||||
ec11_pcnt_clear(0);
|
||||
depth_data->depth_offset = -depth_config->depth_offset;
|
||||
depth_data->depth = depth_config->depth_offset;
|
||||
enc1_value = 0;
|
||||
enc1_update_time = 0;
|
||||
depth_data->up_down = 1; // 默认工作
|
||||
}
|
||||
|
||||
void DEPTH_init()
|
||||
{
|
||||
|
||||
// depth_init();
|
||||
|
||||
pcnt_rotary_encoder_init();
|
||||
capture_depth_init();
|
||||
xTaskCreate(depth_task, "depth_task", 4096, NULL, 10, NULL);
|
||||
}
|
316
main/stm32/flow.c
Normal file
316
main/stm32/flow.c
Normal file
@ -0,0 +1,316 @@
|
||||
#include "stdlib.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "ads1220.h"
|
||||
#include "fram.h"
|
||||
#include "modbuss.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "driver/mcpwm.h"
|
||||
int zero_totalflow_req = 0;
|
||||
const static char *TAG = "flow";
|
||||
|
||||
|
||||
typedef struct capture_event
|
||||
{
|
||||
int ch;
|
||||
uint32_t val;
|
||||
} capture_event_t;
|
||||
|
||||
#define FLOW1_PIN_ECHO GPIO_NUM_9 // 捕获GPIO端口
|
||||
#define FLOW2_PIN_ECHO GPIO_NUM_10 // 捕获GPIO端口
|
||||
#define DEPTH_PIN_ECHO GPIO_NUM_35 // 捕获GPIO端口
|
||||
|
||||
#define TRIGGER_THREAD_PRIORITY 5
|
||||
|
||||
extern int abs_sub(uint32_t enc_update_time, uint32_t _enc_update_time);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t capture_signal;
|
||||
mcpwm_capture_signal_t sel_cap_signal;
|
||||
} capture;
|
||||
|
||||
static uint32_t cap_val_begin_of_flow1 = 0;
|
||||
static uint32_t cap_val_end_of_flow1 = 0;
|
||||
static uint32_t cap_val_begin_of_flow2 = 0;
|
||||
static uint32_t cap_val_end_of_flow2 = 0;
|
||||
|
||||
static xQueueHandle cap_queue;
|
||||
extern uint32_t rtc_clk_apb_freq;
|
||||
uint32_t volatile t15_ccr[2];
|
||||
uint16_t volatile t15_ccr_times[2];
|
||||
|
||||
cal_4_20ma_t *cal_4_20ma = (cal_4_20ma_t *)&gWordVar[CAL_4_20MA_ADDR];
|
||||
flow_config_t *flow_config = (flow_config_t *)&gWordVar[FLOW_CONFIG_ADDR];
|
||||
flow_t *pflow = (flow_t *)&gWordVar[FLOW_REG_ADDR];
|
||||
void capture_flow1_init();
|
||||
void capture_flow2_init();
|
||||
extern void ADS1220_Init(void);
|
||||
|
||||
uint32_t volatile last_ccr[2] = {0};
|
||||
|
||||
extern int ad_value[4];
|
||||
extern int ad_update_time[4];
|
||||
|
||||
extern uint8_t ad_watchdog_cnt;
|
||||
|
||||
extern int ad_values[4];
|
||||
extern int ad_update_time[4];
|
||||
uint32_t flow_update_time[2];
|
||||
uint8_t timeout[2] = {0};
|
||||
int flow_rem[2] = {0};
|
||||
|
||||
static bool flow1_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
||||
void *arg)
|
||||
{
|
||||
// calculate the interval in the ISR,
|
||||
// so that the interval will be always correct even when cap_queue is not handled in time and overflow.
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
|
||||
t15_ccr[0] = edata->cap_value;
|
||||
t15_ccr_times[0]++;
|
||||
return high_task_wakeup == pdFALSE;
|
||||
}
|
||||
|
||||
void capture_flow1_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_1, FLOW1_PIN_ECHO));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pulldown_en(FLOW1_PIN_ECHO));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = flow1_isr_handler, // 绑定流量捕获中断处理函数
|
||||
.user_data = NULL};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP1, &conf));
|
||||
ESP_LOGI(TAG, "capture_flow_init");
|
||||
}
|
||||
|
||||
static bool flow2_isr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata,
|
||||
void *arg)
|
||||
{
|
||||
// calculate the interval in the ISR,
|
||||
// so that the interval will be always correct even when cap_queue is not handled in time and overflow.
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
|
||||
t15_ccr[1] = edata->cap_value;
|
||||
// t15_ccr_times[1] = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
t15_ccr_times[1]++;
|
||||
// send measurement back though queue
|
||||
// xQueueSendFromISR(cap_queue, &cap_event, &high_task_wakeup);
|
||||
|
||||
return high_task_wakeup == pdFALSE;
|
||||
}
|
||||
|
||||
void capture_flow2_init()
|
||||
{
|
||||
ESP_ERROR_CHECK(mcpwm_gpio_init(MCPWM_UNIT_1, MCPWM_CAP_2, FLOW2_PIN_ECHO));
|
||||
// enable pull down CAP0, to reduce noise
|
||||
ESP_ERROR_CHECK(gpio_pulldown_en(FLOW2_PIN_ECHO));
|
||||
// enable both edge capture on CAP0
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_NEG_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = flow2_isr_handler, // 绑定流量捕获中断处理函数
|
||||
.user_data = NULL};
|
||||
ESP_ERROR_CHECK(mcpwm_capture_enable_channel(MCPWM_UNIT_1, MCPWM_SELECT_CAP2, &conf));
|
||||
ESP_LOGI(TAG, "capture_flow_init");
|
||||
}
|
||||
|
||||
// void capture_task(void)
|
||||
// {
|
||||
// while (true) {
|
||||
// capture_event_t cap_event = {.val = 0, .ch = 1};
|
||||
// uint32_t pulse_width_us = 0;
|
||||
// // block and wait for new measurement
|
||||
// // ESP_LOGI(TAG, "xQueueReceive started");
|
||||
// xQueueReceive(cap_queue, &cap_event, portMAX_DELAY);
|
||||
// // ESP_LOGI(TAG, "xQueueReceive after");
|
||||
// // ESP_LOGI(TAG, " cap_event.val: %d, cap_event.ch : %d", cap_event.val, cap_event.ch);
|
||||
// switch (cap_event.ch)
|
||||
// {
|
||||
// case 1: //flow1 capture
|
||||
// pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
|
||||
// ESP_LOGI(TAG, " (flow1 capture) Pulse width: %uus", pulse_width_us);
|
||||
// break;
|
||||
// case 2: //flow2 capture
|
||||
// pulse_width_us = cap_event.val * (1000000.0 / rtc_clk_apb_freq);
|
||||
// ESP_LOGI(TAG, "(flow2 capture) Pulse width: %uus", pulse_width_us);
|
||||
// break;
|
||||
// default: ESP_LOGI(TAG, " default\n");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
void flow_init(void)
|
||||
{
|
||||
// 流量 初始化捕获定时器
|
||||
|
||||
// capture_flow2_init();
|
||||
// MX_TIM15_Init();
|
||||
// HAL_TIM_Base_Start_IT(&htim15);
|
||||
if (flow_config->input_type == 1)
|
||||
{ // 4~20ma
|
||||
// ADS1220_Init();
|
||||
}
|
||||
else if (flow_config->input_type == 2)
|
||||
{ // freq
|
||||
// HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_1);
|
||||
// HAL_TIM_IC_Start_IT(&htim15, TIM_CHANNEL_2);
|
||||
capture_flow1_init();
|
||||
capture_flow2_init();
|
||||
}
|
||||
}
|
||||
extern void zero_totalflow(int ch);
|
||||
void flow_task(void)
|
||||
{
|
||||
static uint32_t cp_flow_tick = 0;
|
||||
static uint32_t ad_flow_tick = 100;
|
||||
int lock_time_out = 0;
|
||||
while (1)
|
||||
{
|
||||
vTaskDelay(50);
|
||||
|
||||
if (flow_config->input_type == 2 && TickDiff(cp_flow_tick) > 100)
|
||||
{
|
||||
int ch;
|
||||
cp_flow_tick = xTaskGetTickCount();
|
||||
for (ch = 0; ch < 2; ch++)
|
||||
{
|
||||
if (t15_ccr_times[ch] > 0)
|
||||
{
|
||||
int ccr_times;
|
||||
int time_diff;
|
||||
uint32_t ccr;
|
||||
// __disable_irq();
|
||||
ccr_times = t15_ccr_times[ch];
|
||||
|
||||
t15_ccr_times[ch] = 0;
|
||||
ccr = t15_ccr[ch];
|
||||
ccr = ccr / (rtc_clk_apb_freq / 1000000);
|
||||
// __enable_irq();
|
||||
time_diff = ccr - last_ccr[ch];
|
||||
ESP_LOGI(TAG, "(type2) t15_ccr_times[%d]: %u %u time_diff: %u", ch, ccr, ccr_times, time_diff);
|
||||
printf("rtc_clk_apb_freq : %u\n", rtc_clk_apb_freq);
|
||||
if (time_diff != 0)
|
||||
{
|
||||
int t_flow;
|
||||
|
||||
pflow[ch].flow_ = flow_config->pulse_coef[ch] * 600 * (int64_t)ccr_times / time_diff;
|
||||
if (pflow[ch].flow_ < flow_config->min_flow[ch])
|
||||
{
|
||||
pflow[ch].flow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pflow[ch].flow = pflow[ch].flow_;
|
||||
}
|
||||
t_flow = pflow[ch].flow * time_diff / (5 * 60);
|
||||
flow_rem[ch] += t_flow;
|
||||
pflow[ch].total_flow += flow_rem[ch] / 10000;
|
||||
flow_rem[ch] = flow_rem[ch] % 10000;
|
||||
pflow[ch].update_time = ccr;
|
||||
last_ccr[ch] = ccr;
|
||||
timeout[ch] = 0;
|
||||
// ESP_LOGI(TAG, "(type2) pflow[%d].flow: %u", ch ,pflow[ch].flow);
|
||||
}
|
||||
}
|
||||
if (++timeout[ch] > 5)
|
||||
{
|
||||
timeout[ch] = 0;
|
||||
pflow[ch].flow = 0;
|
||||
pflow[ch].flow_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flow_config->input_type == 1 && TickDiff(ad_flow_tick) > 200)
|
||||
{
|
||||
int i;
|
||||
ad_flow_cal_t *cal = flow_config->ad_cal;
|
||||
ad_flow_tick = xTaskGetTickCount();
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
int ad_ch = i * 2 + 1;
|
||||
int time_diff = abs_sub(ad_update_time[ad_ch], pflow[i].update_time);
|
||||
if (time_diff != 0)
|
||||
{
|
||||
int t_flow; // time_diff时间段总流量
|
||||
pflow[i].flow_ = scale(ad_value[ad_ch], cal_4_20ma->ch[i].ad_4ma, cal_4_20ma->ch[i].ad_20ma, cal[i].flow_min, cal[i].flow_max);
|
||||
if (pflow[i].flow_ < flow_config->min_flow[i])
|
||||
{
|
||||
pflow[i].flow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pflow[i].flow = pflow[i].flow_;
|
||||
}
|
||||
// 累计流量计算 pflow[i].flow 单位为0.01L/分钟 time_diff 单位为20uS
|
||||
// flow = pflow[i].flow / 60.0 * 10000; 将流量换算成uL/s
|
||||
// t_diff = time_diff / 50000 将时间差换算成秒
|
||||
// t_flow = flow * t_diff 计算t_diff时间段的流量 单位uL
|
||||
// 取出0.01L的整数部分累加,余数部分和下次值累加
|
||||
// t_flow = pflow[i].flow * 1000 * time_diff / 500000 / 60;
|
||||
int time_diff_us = time_diff / (APB_CLK_FREQ / 1000000);
|
||||
t_flow = pflow[i].flow * time_diff_us / 60 / 100;
|
||||
flow_rem[i] += t_flow;
|
||||
pflow[i].total_flow += flow_rem[i] / 10000;
|
||||
flow_rem[i] = flow_rem[i] % 10000;
|
||||
pflow[i].update_time = ad_update_time[ad_ch];
|
||||
timeout[i] = 0;
|
||||
ESP_LOGI(TAG, "(type1) flow_rem[%d].flow: %u", i, pflow[i].flow);
|
||||
}
|
||||
if (++timeout[i] > 10)
|
||||
{
|
||||
timeout[i] = 0;
|
||||
pflow[i].flow = 0;
|
||||
pflow[i].flow_ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(zero_totalflow_req){
|
||||
zero_totalflow_req = 0;
|
||||
zero_totalflow(0);
|
||||
zero_totalflow(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取给定时刻累计流量
|
||||
int get_total_flow_by_time(int ch, uint32_t time)
|
||||
{
|
||||
int delta_t;
|
||||
int delta_flow;
|
||||
if (ch > 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
delta_t = abs_sub(time, pflow[ch].update_time) / (APB_CLK_FREQ / 1000000); // 换算成us
|
||||
delta_flow = pflow[ch].flow * delta_t / 60 / 100;
|
||||
return pflow[ch].total_flow + delta_flow;
|
||||
}
|
||||
|
||||
void zero_totalflow(int ch)
|
||||
{
|
||||
if (ch > 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
pflow[ch].total_flow = 0;
|
||||
flow_rem[ch] = 0;
|
||||
}
|
||||
|
||||
void FLOW_init()
|
||||
{
|
||||
flow_init();
|
||||
xTaskCreate(flow_task, "flow_task", 4096, NULL, 10, NULL);
|
||||
}
|
131
main/stm32/fram.c
Normal file
131
main/stm32/fram.c
Normal file
@ -0,0 +1,131 @@
|
||||
#include "fram.h"
|
||||
#include "string.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char *TAG = "i2c-simple-example";
|
||||
|
||||
#define I2C_MASTER_SCL_IO 1 /*!< GPIO number used for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO 2 /*!< GPIO number used for I2C master data */
|
||||
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
|
||||
#define I2C_MASTER_FREQ_HZ 400000 /*!< I2C master clock frequency */
|
||||
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
|
||||
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
|
||||
#define I2C_MASTER_TIMEOUT_MS 1000
|
||||
|
||||
#define MPU9250_SENSOR_ADDR 0x68 /*!< Slave address of the MPU9250 sensor */
|
||||
#define MPU9250_WHO_AM_I_REG_ADDR 0x75 /*!< Register addresses of the "who am I" register */
|
||||
|
||||
#define MPU9250_PWR_MGMT_1_REG_ADDR 0x6B /*!< Register addresses of the power managment register */
|
||||
#define MPU9250_RESET_BIT 7
|
||||
|
||||
#define WRITE_BIT I2C_MASTER_WRITE
|
||||
#define ACK_CHECK_EN 0x1
|
||||
#define TAG "FREM"
|
||||
|
||||
/**
|
||||
* @brief Read a sequence of bytes from a MPU9250 sensor registers
|
||||
*/
|
||||
// static esp_err_t mpu9250_register_read(uint8_t reg_addr, uint8_t *data, size_t len)
|
||||
// {
|
||||
// return i2c_master_write_read_device(I2C_MASTER_NUM, MPU9250_SENSOR_ADDR, ®_addr, 1, data, len, I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief Write a byte to a MPU9250 sensor register
|
||||
*/
|
||||
// static esp_err_t mpu9250_register_write_byte(uint8_t reg_addr, uint8_t data)
|
||||
// {
|
||||
// int ret;
|
||||
// uint8_t write_buf[2] = {reg_addr, data};
|
||||
|
||||
// ret = i2c_master_write_to_device(I2C_MASTER_NUM, MPU9250_SENSOR_ADDR, write_buf, sizeof(write_buf), I2C_MASTER_TIMEOUT_MS / portTICK_RATE_MS);
|
||||
|
||||
// return ret;
|
||||
// }
|
||||
|
||||
/**
|
||||
* @brief i2c master initialization
|
||||
*/
|
||||
esp_err_t i2c_master_init(void)
|
||||
{
|
||||
int i2c_master_port = I2C_MASTER_NUM;
|
||||
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
|
||||
i2c_param_config(i2c_master_port, &conf);
|
||||
|
||||
return i2c_driver_install(i2c_master_port, conf.mode, I2C_MASTER_RX_BUF_DISABLE, I2C_MASTER_TX_BUF_DISABLE, 0);
|
||||
}
|
||||
|
||||
int fram_write(uint16_t addr, void * buf,uint32_t len)
|
||||
{
|
||||
esp_err_t ret;
|
||||
uint8_t slave_addr = (0xA0) | ((addr >> 8) & 0x7);/*page select*/
|
||||
uint8_t low_addr = addr &0xff;
|
||||
// return HAL_I2C_Mem_Write(&hi2c1,slave_addr,addr&0xff,I2C_MEMADD_SIZE_8BIT,buf,len,200);
|
||||
// ret = i2c_master_write_to_device(I2C_MASTER_NUM, slave_addr, txbuf, len+1, 10);
|
||||
// // ret = i2c_master_write_read_device(I2C_MASTER_NUM, slave_addr, buf, len, 10);
|
||||
// // assert(ret == ESP_OK);
|
||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, slave_addr | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write(cmd, &low_addr, 1, ACK_CHECK_EN);
|
||||
i2c_master_write(cmd, buf, len, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
|
||||
if (ret != ESP_OK) {
|
||||
printf("esp_err : %s \n", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
i2c_cmd_link_delete(cmd);
|
||||
return ret;
|
||||
}
|
||||
int fram_read(uint16_t addr,void * buf,uint32_t len)
|
||||
{
|
||||
// esp_err_t err = i2c_param_config(i2c_master_port, &conf);
|
||||
|
||||
esp_err_t ret;
|
||||
uint8_t slave_addr = (0xA0>>1) | ((addr >> 8) & 0x7);/*page select*/
|
||||
uint8_t low_addr = addr &0xff;
|
||||
// return HAL_I2C_Mem_Read(&hi2c1,slave_addr,addr&0xff,I2C_MEMADD_SIZE_8BIT,buf,len,200);
|
||||
ret = i2c_master_write_read_device(I2C_MASTER_NUM, slave_addr, &low_addr,1, buf, len, 10);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG,"esp_err : %s \n", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
ESP_LOGI(TAG,"fram_read succeed\n");
|
||||
// ESP_LOGI(TAG, "buf value : %d \n ", buf[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void save_para(void)
|
||||
{
|
||||
|
||||
}
|
||||
void save_encode(void)
|
||||
{
|
||||
|
||||
}
|
||||
void read_para()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void clear_para()
|
||||
{
|
||||
|
||||
}
|
31
main/stm32/fram.h
Normal file
31
main/stm32/fram.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef FRAM_H__
|
||||
#define FRAM_H__
|
||||
|
||||
|
||||
|
||||
// #include "main.h"
|
||||
// #include "i2c.h"
|
||||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "driver/i2c.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
|
||||
|
||||
int fram_write(uint16_t addr, void * buf,uint32_t len);
|
||||
int fram_read(uint16_t addr,void * buf,uint32_t len);
|
||||
//extern void fram_write_para(fram_para_t *para,uint32_t len);
|
||||
//extern void fram_read_para(fram_para_t *para,uint32_t len);
|
||||
|
||||
|
||||
void save_para(void);
|
||||
void save_encode(void);
|
||||
void read_para(void);
|
||||
void clear_para(void);
|
||||
#endif
|
||||
|
||||
|
296
main/stm32/master.c
Normal file
296
main/stm32/master.c
Normal file
@ -0,0 +1,296 @@
|
||||
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "string.h"
|
||||
#include "esp_log.h"
|
||||
#include "modbus_params.h" // for modbus parameters structures
|
||||
#include "mbcontroller.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define MB_PORT_NUM (CONFIG_MB_UART_PORT_NUM) // Number of UART port used for Modbus connection
|
||||
#define MB_DEV_SPEED (CONFIG_MB_UART_BAUD_RATE) // The communication speed of the UART
|
||||
|
||||
// Note: Some pins on target chip cannot be assigned for UART communication.
|
||||
// See UART documentation for selected board and target to configure pins using Kconfig.
|
||||
|
||||
// The number of parameters that intended to be used in the particular control process
|
||||
#define MASTER_MAX_CIDS num_device_parameters
|
||||
|
||||
// Number of reading of parameters from slave
|
||||
#define MASTER_MAX_RETRY 30
|
||||
|
||||
// Timeout to update cid over Modbus
|
||||
#define UPDATE_CIDS_TIMEOUT_MS (500)
|
||||
#define UPDATE_CIDS_TIMEOUT_TICS (UPDATE_CIDS_TIMEOUT_MS / portTICK_RATE_MS)
|
||||
|
||||
// Timeout between polls
|
||||
#define POLL_TIMEOUT_MS (1)
|
||||
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
|
||||
|
||||
// The macro to get offset for parameter in the appropriate structure
|
||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
|
||||
// Discrete offset macro
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
|
||||
#define STR(fieldname) ((const char*)( fieldname ))
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||
|
||||
static const char *TAG = "MASTER_TEST";
|
||||
|
||||
// Enumeration of modbus device addresses accessed by master device
|
||||
enum {
|
||||
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
|
||||
};
|
||||
|
||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||
enum {
|
||||
CID_INP_DATA_0 = 0,
|
||||
CID_HOLD_DATA_0,
|
||||
CID_INP_DATA_1,
|
||||
CID_HOLD_DATA_1,
|
||||
CID_INP_DATA_2,
|
||||
CID_HOLD_DATA_2,
|
||||
CID_HOLD_TEST_REG,
|
||||
CID_RELAY_P1,
|
||||
CID_RELAY_P2,
|
||||
CID_COUNT
|
||||
};
|
||||
|
||||
// Example Data (Object) Dictionary for Modbus parameters:
|
||||
// The CID field in the table must be unique.
|
||||
// Modbus Slave Addr field defines slave address of the device with correspond parameter.
|
||||
// Modbus Reg Type - Type of Modbus register area (Holding register, Input Register and such).
|
||||
// Reg Start field defines the start Modbus register number and Reg Size defines the number of registers for the characteristic accordingly.
|
||||
// The Instance Offset defines offset in the appropriate parameter structure that will be used as instance to save parameter value.
|
||||
// Data Type, Data Size specify type of the characteristic and its data size.
|
||||
// Parameter Options field specifies the options that can be used to process parameter value (limits or masks).
|
||||
// Access Mode - can be used to implement custom options for processing of characteristic (Read/Write restrictions, factory mode values and etc).
|
||||
const mb_parameter_descriptor_t device_parameters[] = {
|
||||
// { CID, Param Name, Units, Modbus Slave Addr, Modbus Reg Type, Reg Start, Reg Size, Instance Offset, Data Type, Data Size, Parameter Options, Access Mode}
|
||||
{ CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 0, 2,
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4, OPTS( -10, 10, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 2,
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 10, 58,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 116, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 0, 8,
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U16, 2, OPTS( BIT1, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||
{ CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 8, 8,
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U16, 2, OPTS( BIT0, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER }
|
||||
};
|
||||
|
||||
// Calculate number of parameters in the table
|
||||
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
|
||||
|
||||
// The function to get pointer to parameter storage (instance) according to parameter description table
|
||||
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
|
||||
{
|
||||
assert(param_descriptor != NULL);
|
||||
void* instance_ptr = NULL;
|
||||
if (param_descriptor->param_offset != 0) {
|
||||
switch(param_descriptor->mb_param_type)
|
||||
{
|
||||
case MB_PARAM_HOLDING:
|
||||
instance_ptr = ((void*)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
instance_ptr = ((void*)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
instance_ptr = ((void*)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
instance_ptr = ((void*)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
default:
|
||||
instance_ptr = NULL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
// User operation function to read slave values and check alarm
|
||||
static void master_operation_func(void *arg)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
float value = 0;
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
||||
|
||||
ESP_LOGI(TAG, "Start modbus test...");
|
||||
|
||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++)
|
||||
{
|
||||
// Get data from parameters description table
|
||||
// and use this information to fill the characteristics description table
|
||||
// and having all required fields in just one table
|
||||
err = mbc_master_get_cid_info(cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
|
||||
void* temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
assert(temp_data_ptr);
|
||||
uint8_t type = 0;
|
||||
if ((param_descriptor->param_type == PARAM_TYPE_ASCII) &&
|
||||
(param_descriptor->cid == CID_HOLD_TEST_REG)) {
|
||||
// Check for long array of registers of type PARAM_TYPE_ASCII
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
// Initialize data of test array and write to slave
|
||||
if (*(uint32_t*)temp_data_ptr != 0xAAAAAAAA) {
|
||||
memset((void*)temp_data_ptr, 0xAA, param_descriptor->param_size);
|
||||
*(uint32_t*)temp_data_ptr = 0xAAAAAAAA;
|
||||
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)temp_data_ptr, &type);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
} else {
|
||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||
(uint8_t*)&value, &type);
|
||||
if (err == ESP_OK) {
|
||||
*(float*)temp_data_ptr = value;
|
||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
value,
|
||||
*(uint32_t*)temp_data_ptr);
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
uint16_t state = *(uint16_t*)temp_data_ptr;
|
||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(char*)param_descriptor->param_units,
|
||||
(const char*)rw_str,
|
||||
*(uint16_t*)temp_data_ptr);
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||
param_descriptor->cid,
|
||||
(char*)param_descriptor->param_key,
|
||||
(int)err,
|
||||
(char*)esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
vTaskDelay(POLL_TIMEOUT_TICS); // timeout between polls
|
||||
}
|
||||
}
|
||||
vTaskDelay(UPDATE_CIDS_TIMEOUT_TICS); //
|
||||
}
|
||||
|
||||
if (alarm_state) {
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
|
||||
param_descriptor->cid);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
|
||||
MASTER_MAX_RETRY);
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy master...");
|
||||
ESP_ERROR_CHECK(mbc_master_destroy());
|
||||
}
|
||||
|
||||
// Modbus master initialization
|
||||
static esp_err_t master_init(void)
|
||||
{
|
||||
// Initialize and start Modbus controller
|
||||
mb_communication_info_t comm = {
|
||||
.port = MB_PORT_NUM,
|
||||
#if CONFIG_MB_COMM_MODE_ASCII
|
||||
.mode = MB_MODE_ASCII, //串口
|
||||
#elif CONFIG_MB_COMM_MODE_RTU
|
||||
.mode = MB_MODE_RTU, //RS485
|
||||
#endif
|
||||
.baudrate = MB_DEV_SPEED,
|
||||
.parity = MB_PARITY_NONE
|
||||
};
|
||||
void* master_handler = NULL;
|
||||
|
||||
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
|
||||
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail.");
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller initialization fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
err = mbc_master_setup((void*)&comm);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller setup fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
|
||||
// Set UART pin numbers
|
||||
err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
|
||||
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
|
||||
|
||||
err = mbc_master_start();
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
"mb controller start fail, returns(0x%x).",
|
||||
(uint32_t)err);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||
|
124
main/stm32/uart0_modbus_slave.c
Normal file
124
main/stm32/uart0_modbus_slave.c
Normal file
@ -0,0 +1,124 @@
|
||||
/* UART Echo 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "uart.h"
|
||||
|
||||
static const char *TAG = "UART0";
|
||||
|
||||
#define BAUD_RATE (115200)
|
||||
#define UART_PORT_NUM (0)
|
||||
#define BUF_SIZE (256)
|
||||
#define UART_READ_TOUT (5 / portTICK_RATE_MS)
|
||||
|
||||
#define LED1_GPIO_PIN 11
|
||||
|
||||
uint8_t txbuf[BUF_SIZE];
|
||||
uint8_t rxbuf[BUF_SIZE];
|
||||
extern int ModbusSlaveProcess(uint8_t *txbuf, uint8_t *rxbuf, uint16_t rxLen, int is_crc);
|
||||
|
||||
void uart0_init(void)
|
||||
{
|
||||
const int uart_num = UART_PORT_NUM;
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
// Set UART log level
|
||||
// esp_log_level_set(TAG, ESP_LOG_NONE);
|
||||
|
||||
ESP_LOGI(TAG, "Start RS485 application test and configure UART.");
|
||||
|
||||
// Install UART driver (we don't need an event queue here)
|
||||
// In this example we don't even use a buffer for sending data.
|
||||
ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0));
|
||||
|
||||
// Configure UART parameters
|
||||
ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
|
||||
ESP_LOGI(TAG, "UART set pins, mode and install driver.");
|
||||
// Set UART pins as per KConfig settings
|
||||
// ESP_ERROR_CHECK(uart_set_pin(uart_num, UART_TXD_PIN, UART_RXD_PIN, UART_RTS_PIN, UART_CTS_PIN));
|
||||
// Set RS485 half duplex mode
|
||||
ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
|
||||
// Set read timeout of UART TOUT feature
|
||||
ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, UART_READ_TOUT));
|
||||
}
|
||||
|
||||
void LED1_Toggle(void)
|
||||
{
|
||||
static unsigned char flg = 1;
|
||||
if (flg)
|
||||
{
|
||||
gpio_set_level(LED1_GPIO_PIN, 0);
|
||||
flg = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpio_set_level(LED1_GPIO_PIN, 1);
|
||||
flg = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void uart0_modbus_slave_task(void)
|
||||
{
|
||||
|
||||
while (1)
|
||||
{
|
||||
// Read data from UART
|
||||
int txlen = 0;
|
||||
int len = uart_read_bytes(UART_PORT_NUM, rxbuf, BUF_SIZE, UART_READ_TOUT);
|
||||
uint32_t tick = xTaskGetTickCount();
|
||||
// Write data back to UART
|
||||
if (len > 0)
|
||||
{
|
||||
// uart_write_bytes(UART_PORT_NUM, rxbuf, len);
|
||||
// ESP_LOGI(TAG, "uart_read_bytes len=%d", len);
|
||||
txlen = ModbusSlaveProcess(txbuf, rxbuf, len, 1);
|
||||
if (txlen > 0)
|
||||
{
|
||||
LED1_Toggle();
|
||||
uart_write_bytes(UART_PORT_NUM, txbuf, txlen);
|
||||
}
|
||||
}
|
||||
// if (tick - last_rxtick >= PACKET_READ_TICS)
|
||||
// {
|
||||
// com_poll_modbus_master_poll(0);
|
||||
// // if (++mcu_watch_dog_cnt > mcu_watch_dog_timeout) //如果通讯中断会相互重启,计数器不起作用
|
||||
// if (gpio_get_level(0)) // cpu 启动后会拉低GPIO0
|
||||
// {
|
||||
// mcu_watch_dog_cnt = 0;
|
||||
// if (mcu_pwr_off_cnt < 2)
|
||||
// {
|
||||
// mcu_pwr_off_cnt++;
|
||||
// gpio_set_level(12, 1); // 3v8 off
|
||||
// vTaskDelay(3000 / portTICK_RATE_MS);
|
||||
// gpio_set_level(12, 0); // 3v8 off
|
||||
// mcu_watch_dog_timeout = 12000 / (portTICK_RATE_MS * PACKET_READ_TICS);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// last_rxtick = tick;
|
||||
}
|
||||
}
|
||||
|
||||
void uart0_modbus_slave_init(void)
|
||||
{
|
||||
uart0_init();
|
||||
xTaskCreate(uart0_modbus_slave_task, "uart0_modbus_slave_task", 4096, NULL, 10, NULL);
|
||||
}
|
112
main/stm32/uart1_modbus_master.c
Normal file
112
main/stm32/uart1_modbus_master.c
Normal file
@ -0,0 +1,112 @@
|
||||
/* UART Echo 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "uart.h"
|
||||
|
||||
/**
|
||||
* This is an example which echos any data it receives on configured UART back to the sender,
|
||||
* with hardware flow control turned off. It does not use UART driver event queue.
|
||||
*
|
||||
* - Port: configured UART
|
||||
* - Receive (Rx) buffer: on
|
||||
* - Transmit (Tx) buffer: off
|
||||
* - Flow control: off
|
||||
* - Event queue: off
|
||||
* - Pin assignment: see defines below (See Kconfig)
|
||||
*/
|
||||
|
||||
#define UART_TXD_PIN 17
|
||||
#define UART_RXD_PIN 18
|
||||
#define UART_RTS_PIN 8
|
||||
#define UART_CTS_PIN (-1)
|
||||
|
||||
static const char *TAG = "UART1";
|
||||
|
||||
#define BAUD_RATE (9600)
|
||||
#define UART_PORT_NUM (1)
|
||||
#define RX_BUF_SIZE (256)
|
||||
#define TX_BUF_SIZE (256)
|
||||
|
||||
#define UART_READ_TOUT (5 / portTICK_PERIOD_MS)
|
||||
|
||||
static void uart1_rs485_init(void)
|
||||
{
|
||||
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.rx_flow_ctrl_thresh = 122,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Start RS485 application test and configure UART.");
|
||||
|
||||
// Install UART driver (we don't need an event queue here)
|
||||
// In this example we don't even use a buffer for sending data.
|
||||
ESP_ERROR_CHECK(uart_driver_install(UART_PORT_NUM, RX_BUF_SIZE, TX_BUF_SIZE, 0, NULL, 0));
|
||||
|
||||
// Configure UART parameters
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, &uart_config));
|
||||
|
||||
ESP_LOGI(TAG, "UART set pins, mode and install driver.");
|
||||
|
||||
// Set UART pins as per KConfig settings
|
||||
ESP_ERROR_CHECK(uart_set_pin(UART_PORT_NUM, UART_TXD_PIN, UART_RXD_PIN, UART_RTS_PIN, UART_CTS_PIN));
|
||||
|
||||
// Set RS485 half duplex mode
|
||||
ESP_ERROR_CHECK(uart_set_mode(UART_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
|
||||
|
||||
// Set read timeout of UART TOUT feature
|
||||
ESP_ERROR_CHECK(uart_set_rx_timeout(UART_PORT_NUM, UART_READ_TOUT));
|
||||
}
|
||||
|
||||
static void uart0_com_poll_task(void *arg)
|
||||
{
|
||||
|
||||
uint32_t last_rxtick = 0;
|
||||
uint8_t rx_data[RX_BUF_SIZE];
|
||||
uint8_t tx_data[RX_BUF_SIZE];
|
||||
while (1)
|
||||
{
|
||||
// Read data from UART
|
||||
int len = uart_read_bytes(UART_PORT_NUM, rx_data, RX_BUF_SIZE, UART_READ_TOUT);
|
||||
uint32_t tick = xTaskGetTickCount();
|
||||
// Write data back to UART
|
||||
if (len > 0)
|
||||
{
|
||||
// ESP_LOGI(TAG, "uart_read_bytes len=%d", len);
|
||||
int err = com_poll_modbus_master_on_revice(0, data, len);
|
||||
if (err == 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
if (tick - last_rxtick >= UART_READ_TOUT)
|
||||
{
|
||||
com_poll_modbus_master_poll(0);
|
||||
// if (++mcu_watch_dog_cnt > mcu_watch_dog_timeout) //如果通讯中断会相互重启,计数器不起作用
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void uart1_task_init(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "uart1_com_poll_task");
|
||||
// A uart read/write example without event queue;
|
||||
xTaskCreate(uart0_com_poll_task, "uart0_com_poll_task", 1024, NULL, 9, NULL);
|
||||
}
|
61
main/stm32/uart2_printer.c
Normal file
61
main/stm32/uart2_printer.c
Normal file
@ -0,0 +1,61 @@
|
||||
/* UART Echo 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "uart.h"
|
||||
|
||||
/**
|
||||
* This is an example which echos any data it receives on configured UART back to the sender,
|
||||
* with hardware flow control turned off. It does not use UART driver event queue.
|
||||
*
|
||||
* - Port: configured UART
|
||||
* - Receive (Rx) buffer: on
|
||||
* - Transmit (Tx) buffer: off
|
||||
* - Flow control: off
|
||||
* - Event queue: off
|
||||
* - Pin assignment: see defines below (See Kconfig)
|
||||
*/
|
||||
|
||||
#define UART_TXD_PIN 16
|
||||
#define UART_RXD_PIN 15
|
||||
#define UART_RTS_PIN (-1)
|
||||
#define UART_CTS_PIN 3
|
||||
|
||||
static const char *TAG = "UART2";
|
||||
#define UART2_BAUD_RATE (115200)
|
||||
#define UART_PORT_NUM (2)
|
||||
#define BUF_SIZE (1024)
|
||||
|
||||
static void uart2_init(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = UART2_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(UART_PORT_NUM, UART_TXD_PIN, UART_RXD_PIN, UART_RTS_PIN, UART_CTS_PIN));
|
||||
}
|
||||
|
||||
|
60
main/stm32/utils.c
Normal file
60
main/stm32/utils.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
int GetCompileDateTime(uint16_t *DateTime)
|
||||
{
|
||||
const int MONTH_PER_YEAR=13;
|
||||
static char szEnglishMonth[][4] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
|
||||
char szTmpDate[40]= {0};
|
||||
char szTmpTime[20]= {0};
|
||||
char szMonth[4]= {0};
|
||||
int iYear,iMonth,iDay,iHour,iMin,iSec;//,,
|
||||
int i;
|
||||
//获取编译日期、时间
|
||||
sprintf(szTmpDate,"%s",__DATE__); //"Sep 18 2010"
|
||||
sprintf(szTmpTime,"%s",__TIME__); //"10:59:19"
|
||||
|
||||
sscanf(szTmpDate,"%s %d %d",szMonth,&iDay,&iYear);
|
||||
sscanf(szTmpTime,"%d:%d:%d",&iHour,&iMin,&iSec);
|
||||
|
||||
for(i=0; MONTH_PER_YEAR; i++)
|
||||
{
|
||||
if(strncmp(szMonth,szEnglishMonth[i],3)==0)
|
||||
{
|
||||
iMonth=i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("%d,%d,%d,%d,%d,%d\n",iYear,iMonth,iDay,iHour,iMin,iSec);
|
||||
//sprintf(szDateTime,"%04d-%02d-%02d %02d:%02d:%02d",iYear,iMonth,iDay,iHour,iMin,iSec);
|
||||
DateTime[0] = iYear;
|
||||
DateTime[1] = iMonth*100;
|
||||
DateTime[1] += iDay;
|
||||
DateTime[2] = iHour*100;
|
||||
DateTime[2] += iMin;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int TickDiff(unsigned int comptime)
|
||||
{
|
||||
unsigned int nowtime = xTaskGetTickCount();
|
||||
if(nowtime >= comptime)
|
||||
return (nowtime - comptime);
|
||||
else
|
||||
return (0 - (comptime - nowtime));
|
||||
}
|
||||
|
||||
int scale(int raw, int raw_min, int raw_max,int eng_min, int eng_max)
|
||||
{
|
||||
int result = 0;
|
||||
if(raw_max != raw_min)
|
||||
{
|
||||
result = (raw - raw_min) * (eng_max - eng_min) / (raw_max - raw_min) + eng_min;
|
||||
}
|
||||
return result;
|
||||
}
|
6
main/stm32/utils.h
Normal file
6
main/stm32/utils.h
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
int GetCompileDateTime(uint16_t *DateTime);
|
||||
extern unsigned int TickDiff(unsigned int comptime);
|
||||
#endif
|
28
main/uart.h
Normal file
28
main/uart.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef _UART_H_
|
||||
#define _UART_H_
|
||||
|
||||
#define RS485_TXD_PIN 17
|
||||
#define RS485_RXD_PIN 18
|
||||
#define RS485_RTS_PIN 8
|
||||
#define RS485_CTS_PIN (-1)
|
||||
|
||||
// #define MCU_TXD_PIN 17
|
||||
// #define MCU_RXD_PIN 18
|
||||
|
||||
|
||||
#define PRINT_TXD_PIN 16
|
||||
#define PRINT_RXD_PIN 15
|
||||
#define PRINT_RTS_PIN (-1)
|
||||
#define PRINT_CTS_PIN 3
|
||||
|
||||
|
||||
#define RS485_UART_PORT_NUM (0)
|
||||
#define RS485_UART_BAUD_RATE (115200)
|
||||
#define RS485_TASK_STACK_SIZE (1024)
|
||||
|
||||
#define PRINT_UART_PORT_NUM (1)
|
||||
#define PRINT_UART_BAUD_RATE (115200)
|
||||
#define PRINT_TASK_STACK_SIZE (1024)
|
||||
|
||||
|
||||
#endif
|
97
main/uart_example.c
Normal file
97
main/uart_example.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* UART Echo 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 "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "uart.h"
|
||||
|
||||
/**
|
||||
* This is an example which echos any data it receives on configured UART back to the sender,
|
||||
* with hardware flow control turned off. It does not use UART driver event queue.
|
||||
*
|
||||
* - Port: configured UART
|
||||
* - Receive (Rx) buffer: on
|
||||
* - Transmit (Tx) buffer: off
|
||||
* - Flow control: off
|
||||
* - Event queue: off
|
||||
* - Pin assignment: see defines below (See Kconfig)
|
||||
*/
|
||||
|
||||
#define RS485_TXD_PIN 17
|
||||
#define RS485_RXD_PIN 18
|
||||
#define RS485_RTS_PIN 8
|
||||
#define RS485_CTS_PIN (-1)
|
||||
|
||||
// #define MCU_TXD_PIN 17
|
||||
// #define MCU_RXD_PIN 18
|
||||
|
||||
|
||||
#define PRINT_TXD_PIN 16
|
||||
#define PRINT_RXD_PIN 15
|
||||
#define PRINT_RTS_PIN (-1)
|
||||
#define PRINT_CTS_PIN 3
|
||||
|
||||
|
||||
#define RS485_UART_PORT_NUM (0)
|
||||
#define RS485_UART_BAUD_RATE (115200)
|
||||
#define RS485_TASK_STACK_SIZE (1024)
|
||||
|
||||
#define PRINT_UART_PORT_NUM (1)
|
||||
#define PRINT_UART_BAUD_RATE (115200)
|
||||
#define PRINT_TASK_STACK_SIZE (1024)
|
||||
|
||||
static const char *TAG = "UART";
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
|
||||
void RS485_init(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = RS485_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(RS485_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(RS485_UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(RS485_UART_PORT_NUM, RS485_TXD_PIN, RS485_RXD_PIN, RS485_RTS_PIN, RS485_CTS_PIN));
|
||||
}
|
||||
|
||||
void print_init(void)
|
||||
{
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = PRINT_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_APB,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(uart_driver_install(PRINT_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
ESP_ERROR_CHECK(uart_param_config(PRINT_UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(PRINT_UART_PORT_NUM, PRINT_TXD_PIN, PRINT_RXD_PIN, PRINT_RTS_PIN, PRINT_CTS_PIN));
|
||||
}
|
154
main/wifi_softap.c
Normal file
154
main/wifi_softap.c
Normal file
@ -0,0 +1,154 @@
|
||||
/* WiFi softAP 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#include "driver/ledc.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
/* The examples use WiFi configuration that you can set via project configuration menu.
|
||||
|
||||
If you'd rather not, just change the below entries to strings with
|
||||
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
|
||||
*/
|
||||
#define ESP_WIFI_SSID "T2N_056455"
|
||||
#define ESP_WIFI_PASS "01010101"
|
||||
#define ESP_WIFI_CHANNEL 1
|
||||
#define MAX_STA_CONN 8
|
||||
|
||||
static const char *TAG = "wifi softAP";
|
||||
|
||||
#define LEDC_TIMER LEDC_TIMER_0
|
||||
#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
#define LEDC_OUTPUT_IO (21) // Define the output GPIO
|
||||
#define LEDC_CHANNEL LEDC_CHANNEL_0
|
||||
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
|
||||
#define LEDC_DUTY (4095) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095
|
||||
#define LEDC_FREQUENCY (3840) // Frequency in Hertz. Set frequency at 5 kHz
|
||||
|
||||
static void wifi_event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_id == WIFI_EVENT_AP_STACONNECTED)
|
||||
{
|
||||
wifi_event_ap_staconnected_t *event = (wifi_event_ap_staconnected_t *)event_data;
|
||||
ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
}
|
||||
else if (event_id == WIFI_EVENT_AP_STADISCONNECTED)
|
||||
{
|
||||
wifi_event_ap_stadisconnected_t *event = (wifi_event_ap_stadisconnected_t *)event_data;
|
||||
ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d",
|
||||
MAC2STR(event->mac), event->aid);
|
||||
}
|
||||
}
|
||||
extern void ModBusTCPSlave_init(void);
|
||||
void wifi_init_softap(void)
|
||||
{
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_netif_create_default_wifi_ap();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&wifi_event_handler,
|
||||
NULL,
|
||||
NULL));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
.ssid = ESP_WIFI_SSID,
|
||||
.ssid_len = strlen(ESP_WIFI_SSID),
|
||||
.channel = ESP_WIFI_CHANNEL,
|
||||
.password = ESP_WIFI_PASS,
|
||||
.max_connection = MAX_STA_CONN,
|
||||
.authmode = WIFI_AUTH_WPA_WPA2_PSK},
|
||||
};
|
||||
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("wifi", NVS_READWRITE, &my_handle);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
size_t len;
|
||||
char temp_str[64];
|
||||
uint8_t channel;
|
||||
if (nvs_get_str(my_handle, "ap_ssid", temp_str, &len) == ESP_OK)
|
||||
{
|
||||
strncpy((char*)wifi_config.ap.ssid, temp_str, len);
|
||||
wifi_config.ap.ssid_len = len;
|
||||
}
|
||||
if (nvs_get_str(my_handle, "ap_psk", temp_str, &len) == ESP_OK)
|
||||
{
|
||||
strncpy((char*)wifi_config.ap.password, temp_str, len);
|
||||
}
|
||||
if (nvs_get_u8(my_handle, "ap_ch", &channel) == ESP_OK)
|
||||
{
|
||||
wifi_config.ap.channel = channel;
|
||||
}
|
||||
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
if (strlen(ESP_WIFI_PASS) == 0)
|
||||
{
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
|
||||
ESP_WIFI_SSID, ESP_WIFI_PASS, ESP_WIFI_CHANNEL);
|
||||
}
|
||||
|
||||
// void app_main2(void)
|
||||
// {
|
||||
// // Initialize NVS
|
||||
// esp_err_t ret = nvs_flash_init();
|
||||
// if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
// {
|
||||
// ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
// ret = nvs_flash_init();
|
||||
// }
|
||||
// ESP_ERROR_CHECK(ret);
|
||||
|
||||
// ESP_LOGI(TAG, "ESP_WIFI_MODE_AP");
|
||||
// wifi_init_softap();
|
||||
// // ledc_init();
|
||||
// // ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
|
||||
// // // Update duty to apply the new value
|
||||
// // ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
|
||||
// // gpio_config_t io_conf = {};
|
||||
// // // disable interrupt
|
||||
// // io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
// // // set as output mode
|
||||
// // io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
// // // bit mask of the pins that you want to set,e.g.GPIO18/19
|
||||
// // io_conf.pin_bit_mask = 1 << 9;
|
||||
// // // disable pull-down mode
|
||||
// // io_conf.pull_down_en = 0;
|
||||
// // // disable pull-up mode
|
||||
// // io_conf.pull_up_en = 0;
|
||||
// // // configure GPIO with the given settings
|
||||
// // gpio_config(&io_conf);
|
||||
// // gpio_set_level(9, 1);
|
||||
// }
|
Loading…
Reference in New Issue
Block a user