Interrupts in RT-Thread trigger MicroPython functions

Yesterday, I completed the binding of C functions and Python, which can realize the function of calling C through Python. For specific articles, please refer to:

https://blog.csdn.net/suolong123/article/details/108982925

 

The next task is to implement calling Python functions in C language.

My idea is that by registering a Python function to the listener, when a keypress interrupt is triggered, the Python function is called.

That is to say, these functions are not written into the code in advance, but are implemented by dynamic registration.

A special method to be used here is mp_sched_schedule, which provides a method for C to call Python, but this method seems to only be able to pass one parameter in the past, and there is no time to pass in multiple parameters to use that method.

Without further ado, start coding!

 

The first step is to extend a lollipop_arrive method to children_obj_t on the basis of yesterday's code, and define an active_children as the last active class to let C know whose event should be triggered. At the same time, make a simple modification to the mars_children_make_new method and add a line of active_children =self; the code is as follows:

typedef struct _children_obj_t

{

    mp_obj_base_t   base;       // The defined object structure should contain this member

    char*       name;           // member function

    uint8_t     age;

    uint8_t     sex;

    mp_obj_t    lollipop_arrive;    //The callback function when the lollipop arrives

    

}children_obj_t;



children_obj_t* active_children;

STATIC mp_obj_t mars_children_make_new(const mp_obj_type_t *type,

    size_t n_args , size_t n_kw,const mp_obj_t *args)

{

    mp_arg_check_num(n_args ,n_kw,1,3,true);            // Check the number of parameters, at least 1 parameter, at most 3 parameters

    children_obj_t *self = m_new_obj(children_obj_t);   // Create objects, allocate space

    self->base.type = &mars_children_type;              // define object type

    if(n_args >=1 )

    { self->name = mp_obj_str_get_str(args[0]); }

    if(n_args >=2 )

    { self->age = mp_obj_get_int(args[1]); }

    if(n_args ==3 )

    { self->sex = mp_obj_get_int(args[2]); }

    printf("Create a new children , name:%s , age:%d , sex:%s\n"

    ,self->name,self->age,self->sex==0?"girl":"boy");

    active_children=self;     //Set the last defined object as the active object

    return MP_OBJ_FROM_PTR(self);                       //return object

}

Only the bolded part is modified, the others are the same as yesterday.

 

The second step, write the interrupt trigger function and the listener registration function, and define the dictionary, and finally don't forget QDEF(MP_QSTR_set_fun, (const byte*)"\x85\x07" "set_fun")

//interrupt service function

void Key_Handler(void* args)

{

    rt_interrupt_enter();   //Notify the operating system to enter the interrupted state at this time

    

    int16_t key;

    memcpy(&key, (void *)&args, sizeof(int16_t));

    mp_sched_schedule(active_children->lollipop_arrive, MP_OBJ_FROM_PTR(mp_obj_new_int(key)));

    rt_kprintf("KeyOn %d!\n",key);

    //call Python

    

    rt_interrupt_leave();   //Notifies the operating system to leave the interrupted state at this time

}

//listener setup function

STATIC mp_obj_t mars_children_set_fun(mp_obj_t self_in , mp_obj_t fun)

{

    children_obj_t *self = MP_OBJ_TO_PTR(self_in);

    self->lollipop_arrive = fun;

    

    return mp_const_none;

}

STATIC MP_DEFINE_CONST_FUN_OBJ_2(mars_children_set_fun_obj,mars_children_set_fun);



STATIC const mp_rom_map_elem_t children_locals_dict_table[] = {

    { MP_ROM_QSTR(MP_QSTR_sayhello),MP_ROM_PTR(&mars_children_sayhello_obj) },

    { MP_ROM_QSTR(MP_QSTR_set_fun),MP_ROM_PTR(&mars_children_set_fun_obj) },

};

In the previous code, it is mainly the use of the mp_sched_schedule function. The function has two parameters, the first is the method to call, and the second is a parameter passed in. At present, only single-parameter transmission and multi-parameter transmission have been studied. Go back and try to solve it with an array. The following line of printing is used for testing and will not be output in Python. Here we need to remind everyone that this kind of call should be done in the way of inter-thread communication as much as possible, and try not to process any transactions in the interrupt, so our method is only used as an example reference.

 

The third step, the installation is interrupted, this can be written in the main function

// Installation interrupted

rt_pin_mode(KEY_1,PIN_MODE_INPUT_PULLDOWN);     //pull-up input

rt_pin_attach_irq(KEY_1,PIN_IRQ_MODE_RISING,Key_Handler,(void*)1);   //On rising edge

rt_pin_irq_enable(KEY_1,PIN_IRQ_ENABLE);        //enable interrupt

rt_pin_mode(KEY_2,PIN_MODE_INPUT_PULLDOWN);     //pull-up input

rt_pin_attach_irq(KEY_2,PIN_IRQ_MODE_RISING,Key_Handler,(void*)2);   //On rising edge

rt_pin_irq_enable(KEY_2,PIN_IRQ_ENABLE);        //enable interrupt

 

Two buttons are registered here, PA0 and PC13 (this depends on your board)

 

Well, the overall code is complete, burn into the board, and we start to write the python part.

As a reminder here, it's best to test whether your interrupt is triggered before entering Python. When I wrote it for the first time, I found that the pins were wrong, and the life and death were not interrupted. I thought that there was a problem with the Python writing, and the final test was a GPIO problem... Unit testing is still necessary.

 

After booting up, I entered Python. I entered it with mpy_main in main. If I started it with a file, it would exit after execution, and I could not test the interruption.

In the Python code, the main process is to define a children instance, then inject a trigger function into this instance, and finally, trigger the function through the entity button.

import mars

e = mars.children("Claire",8,0)

def lollipop(num):

print("Thank you for the lollipop:%d"%(num))







e.set_fun(lollipop)

This code is sent through the serial debugging assistant. After defining the method, don't manually enter the space, just enter the content directly, and then the following three empty lines are to jump out of the method definition and continue to execute the following. This function has only one parameter, and an error will be reported if there is more.

set_fun injects this function into the listener, and then the interrupt can be started.


 

>>> import mars

>>> e = mars.children("Claire",8,0)

Create a new children , name:Claire , age:8 , sex:girl

>>> def lollipop(num):

...     print("Thank you for the lollipop:%d"%(num))

...     

...     

...

>>> e.set_fun(lollipop)

>>> Thank you for the lollipop:1

Thank you for the lollipop:2

 

Tags: Python stm32

Posted by jdsflash on Thu, 12 May 2022 20:48:03 +0300