| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /* Pulse counter module - Example
- For other examples please check:
- https://github.com/espressif/esp-idf/tree/master/examples
- 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/portmacro.h"
- #include "freertos/task.h"
- #include "freertos/queue.h"
- #include "driver/periph_ctrl.h"
- #include "driver/ledc.h"
- #include "driver/gpio.h"
- #include "driver/pcnt.h"
- #include "esp_attr.h"
- #include "esp_log.h"
- /**
- * TEST CODE BRIEF
- *
- * Use PCNT module to count rising edges generated by LEDC module.
- *
- * Functionality of GPIOs used in this example:
- * - GPIO18 - output pin of a sample 1 Hz pulse generator,
- * - GPIO4 - pulse input pin,
- * - GPIO5 - control input pin.
- *
- * Load example, open a serial port to view the message printed on your screen.
- *
- * To do this test, you should connect GPIO18 with GPIO4.
- * GPIO5 is the control signal, you can leave it floating with internal pull up,
- * or connect it to ground. If left floating, the count value will be increasing.
- * If you connect GPIO5 to GND, the count value will be decreasing.
- *
- * An interrupt will be triggered when the counter value:
- * - reaches 'thresh1' or 'thresh0' value,
- * - reaches 'l_lim' value or 'h_lim' value,
- * - will be reset to zero.
- */
- #define PCNT_TEST_UNIT PCNT_UNIT_0
- #define PCNT_H_LIM_VAL 10
- #define PCNT_L_LIM_VAL -10
- #define PCNT_THRESH1_VAL 5
- #define PCNT_THRESH0_VAL -5
- #define PCNT_INPUT_SIG_IO 4 // Pulse Input GPIO
- #define PCNT_INPUT_CTRL_IO 5 // Control GPIO HIGH=count up, LOW=count down
- #define LEDC_OUTPUT_IO 18 // Output GPIO of a sample 1 Hz pulse generator
- xQueueHandle pcnt_evt_queue; // A queue to handle pulse counter events
- pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle
- /* A sample structure to pass events from the PCNT
- * interrupt handler to the main program.
- */
- typedef struct {
- int unit; // the PCNT unit that originated an interrupt
- uint32_t status; // information on the event type that caused the interrupt
- } pcnt_evt_t;
- /* Decode what PCNT's unit originated an interrupt
- * and pass this information together with the event type
- * the main program using a queue.
- */
- static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
- {
- uint32_t intr_status = PCNT.int_st.val;
- int i;
- pcnt_evt_t evt;
- portBASE_TYPE HPTaskAwoken = pdFALSE;
- for (i = 0; i < PCNT_UNIT_MAX; i++) {
- if (intr_status & (BIT(i))) {
- evt.unit = i;
- /* Save the PCNT event type that caused an interrupt
- to pass it to the main program */
- evt.status = PCNT.status_unit[i].val;
- PCNT.int_clr.val = BIT(i);
- xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
- if (HPTaskAwoken == pdTRUE) {
- portYIELD_FROM_ISR();
- }
- }
- }
- }
- /* Configure LED PWM Controller
- * to output sample pulses at 1 Hz with duty of about 10%
- */
- static void ledc_init(void)
- {
- // Prepare and then apply the LEDC PWM timer configuration
- ledc_timer_config_t ledc_timer;
- ledc_timer.speed_mode = LEDC_LOW_SPEED_MODE;
- ledc_timer.timer_num = LEDC_TIMER_1;
- ledc_timer.duty_resolution = LEDC_TIMER_10_BIT;
- ledc_timer.freq_hz = 1; // set output frequency at 1 Hz
- ledc_timer.clk_cfg = LEDC_AUTO_CLK;
- ledc_timer_config(&ledc_timer);
- // Prepare and then apply the LEDC PWM channel configuration
- ledc_channel_config_t ledc_channel;
- ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;
- ledc_channel.channel = LEDC_CHANNEL_1;
- ledc_channel.timer_sel = LEDC_TIMER_1;
- ledc_channel.intr_type = LEDC_INTR_DISABLE;
- ledc_channel.gpio_num = LEDC_OUTPUT_IO;
- ledc_channel.duty = 100; // set duty at about 10%
- ledc_channel.hpoint = 0;
- ledc_channel_config(&ledc_channel);
- }
- /* Initialize PCNT functions:
- * - configure and initialize PCNT
- * - set up the input filter
- * - set up the counter events to watch
- */
- static void pcnt_example_init(void)
- {
- /* Prepare configuration for the PCNT unit */
- pcnt_config_t pcnt_config = {
- // Set PCNT input signal and control GPIOs
- .pulse_gpio_num = PCNT_INPUT_SIG_IO,
- .ctrl_gpio_num = PCNT_INPUT_CTRL_IO,
- .channel = PCNT_CHANNEL_0,
- .unit = PCNT_TEST_UNIT,
- // What to do on the positive / negative edge of pulse input?
- .pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
- .neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge
- // What to do when control input is low or high?
- .lctrl_mode = PCNT_MODE_REVERSE, // Reverse counting direction if low
- .hctrl_mode = PCNT_MODE_KEEP, // Keep the primary counter mode if high
- // Set the maximum and minimum limit values to watch
- .counter_h_lim = PCNT_H_LIM_VAL,
- .counter_l_lim = PCNT_L_LIM_VAL,
- };
- /* Initialize PCNT unit */
- pcnt_unit_config(&pcnt_config);
- /* Configure and enable the input filter */
- pcnt_set_filter_value(PCNT_TEST_UNIT, 100);
- pcnt_filter_enable(PCNT_TEST_UNIT);
- /* Set threshold 0 and 1 values and enable events to watch */
- pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL);
- pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_1);
- pcnt_set_event_value(PCNT_TEST_UNIT, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL);
- pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_THRES_0);
- /* Enable events on zero, maximum and minimum limit values */
- pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_ZERO);
- pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_H_LIM);
- pcnt_event_enable(PCNT_TEST_UNIT, PCNT_EVT_L_LIM);
- /* Initialize PCNT's counter */
- pcnt_counter_pause(PCNT_TEST_UNIT);
- pcnt_counter_clear(PCNT_TEST_UNIT);
- /* Register ISR handler and enable interrupts for PCNT unit */
- pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle);
- pcnt_intr_enable(PCNT_TEST_UNIT);
- /* Everything is set up, now go to counting */
- pcnt_counter_resume(PCNT_TEST_UNIT);
- }
- void app_main(void)
- {
- /* Initialize LEDC to generate sample pulse signal */
- ledc_init();
- /* Initialize PCNT event queue and PCNT functions */
- pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));
- pcnt_example_init();
- int16_t count = 0;
- pcnt_evt_t evt;
- portBASE_TYPE res;
- while (1) {
- /* Wait for the event information passed from PCNT's interrupt handler.
- * Once received, decode the event type and print it on the serial monitor.
- */
- res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
- if (res == pdTRUE) {
- pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
- printf("Event PCNT unit[%d]; cnt: %d\n", evt.unit, count);
- if (evt.status & PCNT_EVT_THRES_1) {
- printf("THRES1 EVT\n");
- }
- if (evt.status & PCNT_EVT_THRES_0) {
- printf("THRES0 EVT\n");
- }
- if (evt.status & PCNT_EVT_L_LIM) {
- printf("L_LIM EVT\n");
- }
- if (evt.status & PCNT_EVT_H_LIM) {
- printf("H_LIM EVT\n");
- }
- if (evt.status & PCNT_EVT_ZERO) {
- printf("ZERO EVT\n");
- }
- } else {
- pcnt_get_counter_value(PCNT_TEST_UNIT, &count);
- printf("Current counter value :%d\n", count);
- }
- }
- if(user_isr_handle) {
- //Free the ISR service handle.
- esp_intr_free(user_isr_handle);
- user_isr_handle = NULL;
- }
- }
|