micropython中断优先级_micropython/ports/m480 at master · XIVN1987/micropython · GitHub

这篇博客介绍了如何在Nuvoton M480 Cortex-M4微控制器上使用MicroPython进行GPIO操作,包括中断设置、定时器、计数器、UART、SPI、I2C、ADC、DAC、PWM和CAN通信。重点讲解了中断优先级的配置,并提供了丰富的代码示例,展示了如何实现各种功能。
摘要由CSDN通过智能技术生成

MicroPython port to Nuvoton M480 (Cortex-M4 MCU)

Pin

输出

import machine

from machine import Pin

led = machine.Pin('PC6', Pin.OUT)

led.low()

led.high()

led.toggle()

led.value(1 - led.value())

输入

key = machine.Pin('PC14', Pin.IN, pull=Pin.PULL_UP)

key.value()

中断

led = machine.Pin('PC6', Pin.OUT)

key = machine.Pin('PC14', Pin.IN, pull=Pin.PULL_UP, irq=Pin.FALL_EDGE, callback=lambda key: led.toggle())

API

Pin(id, dir=Pin.IN, *, af=0, pull=Pin.PULL_NONE, irq=0, callback=None, priority=3)

参数

含义

可取值

dir

GPIO方向

IN、OUT、OPEN_DRAIN

af

引脚功能,0表示GPIO

pull

上下拉控制

PULL_UP、PULL_DOWN、PULL_NONE

irq

中断触发边沿

RISE_EDGE、FALL_EDGE、BOTH_EDGE、LOW_LEVEL、HIGH_LEVEL

callback

中断回调函数

priority

中断优先级

0--7,数值越小优先级越高

Timer

定时器

import machine

from machine import Pin, Timer

led = machine.Pin('PC6', Pin.OUT)

tmr = machine.Timer(0, 100000, callback=lambda tmr: led.toggle()) # 100000us

tmr.start()

定时器模式下单位为us,最大取值为0xFFFFFF = 16777215(约16秒)

计数器

ctr = machine.Timer(1, 3, mode=Timer.COUNTER, pin='PC14', edge=Timer.EDGE_FALLING, callback=lambda ctr: led.toggle())

ctr.start()

计数器模式下单位为计数沿个数,最大取值为0xFFFFFF

如何查询计数器输入在哪个引脚上?

for name in dir(machine.Pin):

if 'TM1' in name:

print(name)

测脉宽

pin = machine.Pin('PA9', Pin.OUT)

pin.low()

cap = machine.Timer(1, 0xFFFFFF, mode=Timer.CAPTURE, pin='PA10', edge=Timer.EDGE_RISING_FALLING)

cap.start()

cap.cap_start()

pin.high(); time.sleep_ms(10); pin.low()

if cap.cap_done():

cap.cap_value() / (machine.freq() / cap.prescale())

将PA9与PA10用杜邦线连接,在PA9上输出一个10ms宽的高脉冲,用Timer1捕获功能测量脉冲的宽度

API

Timer(id, period, *, mode=Timer.TIMER, pin=None, edge=Timer.EDGE_FALLING, trigger=0, prescale=None

irq=Timer.IRQ_TIMEOUT, callback=None, priority=3)

参数

含义

可取值

id

0、1、2、3

period

周期

最大值0xFFFFFF

mode

工作模式

TIMER、COUNTER、CAPTURE

pin

计数和捕获引脚

edge

计数和捕获边沿

EDGE_FALLING、EDGE_RISING、EDGE_FALLING_RISING、EDGE_RISING_FALLING

trigger

超时触发其他外设

TO_ADC、TO_DAC、TO_DMA、TO_PWM 及其或运算

prescale

预分频

1--256

irq

中断触发源

0、IRQ_TIMEOUT、IRQ_CAPTURE 及其或运算

callback

中断回调函数

priority

中断优先级

0--7,数值越小优先级越高

创建Timer实例时,若参数prescale取值为None,则Timer的预分频值如下:

定时器模式下:为 CyclesPerUs,因此定时单位为us

计数器模式或捕获模式下:为 1

prescale([int])

获取或设置预分频,注意:定时器模式下修改预分频后,定时单位就不是us了

period([int])

value()

获取或设置周期值,定时器模式下单位为us,计数器模式下单位为计数沿个数

获取计数器当前值,定时器模式下单位为us,计数器模式下单位为计数沿个数

cap_start([edge])

开启脉宽测量,测量完成后会自动关闭,若想再次测量需要再次调用此方法

开启测量的同时可以通过edge参数指定要捕获的脉冲类型,注意通过此参数设定是持久性的,即后面不带参数调用cap_start()时使用新的设定

cap_done()

cap_value()

cap_done()用于检查测量是否完成;cap_value()用于获取测量到的脉宽值

irq_enable(irq)

irq_disable(irq)

irq_flags(): irq

irq取值为 IRQ_TIMEOUT、IRQ_CAPTURE 及其或运算

UART

import machine

from machine import UART

ser = machine.UART(1, 115200, rxd='PA2', txd='PA3')

ser.write('Hi from MicroPy')

while ser.any() < 7: pass

ser.read()

UART0用于终端交互,请勿使用

中断接收

led = machine.Pin('PC6', Pin.OUT)

def on_ser_rx(ser):

if ser.irq_flags() & ser.IRQ_RXAny:

while ser.any():

char = ser.readchar()

os.dupterm().writechar(char) # do something on received char

if ser.irq_flags() & ser.IRQ_TIMEOUT:

led.toggle() # do something when no data before timeout

ser = machine.UART(1, 57600, rxd='PA2', txd='PA3', irq=UART.IRQ_RXAny, callback=on_ser_rx)

注意1:中断服务程序中GC被锁,不能动态分配内存,因此callback函数中不能使用read和readline,也不能用print

注意2:readchar底层利用了SysTick延时功能,因此UART1的中断优先级不能高于SysTick,SysTick的中断优先级为3

中断发送

class tx_helper:

@classmethod

def send(cls, ser, msg):

cls.Inx = 0

cls.Msg = msg

ser.irq_enable(ser.IRQ_TXEmpty) # when want send message, enable irq

@classmethod

def on_tx(cls, ser):

if ser.irq_flags() & ser.IRQ_TXEmpty:

while not ser.full():

if cls.Inx < len(cls.Msg):

ser.writechar(cls.Msg[cls.Inx])

cls.Inx += 1

else:

ser.irq_disable(ser.IRQ_TXEmpty) # when message sent, disable irq

break

ser = machine.UART(1, 115200, rxd='PA2', txd='PA3', irq=UART.IRQ_TXEmpty, callback=lambda ser: tx_helper.on_tx(ser))

tx_helper.send(ser, b'Hi from MicroPy on NuMicro M480\n')

注意:由于str的索引会导致动态内存分配,因此只能发送bytes

API

UART(id, baudrate, *, bits=8, parity=None, stop=1, rxd=None, txd=None,

irq=0, callback=None, priority=4, timeout=10)

参数

含义

可取值

id

1、2、3、4、5

baudrate

串口波特率

bits

数据位宽

5、6、7、8

parity

校验位

'None'、'Odd'、'Even'、'One'、'Zero'

stop

停止位宽

1、2

rxd

UART_RXD引脚

txd

UART_TXD引脚

irq

中断触发源

0、IRQ_RXAny、IRQ_TXEmpty 及其或运算

callback

中断回调函数

priority

中断优先级

0--7,数值越小优先级越高

timeout

timeout个字符时间未收到新数据触发超时

0--25

baudrate([int])

获取或设置波特率

read([nbytes])

readinto(buf[, nbytes])

readline()

若不指定读取个数,read和readinto读取所有已接收到的内容;readline一直读取直到遇到换行符

write(buf)

buf是实现buffer协议的对象(如str、bytearray)

irq_enable(irq)

irq_disable(irq)

irq_flags(): irq

irq取值为 IRQ_RXAny、IRQ_TXEmpty 及其或运算

SPI

读写闪存

import machine, time

from machine import Pin, SPI

from array import array

spi = machine.SPI(1, 1000000, mosi='PB4', miso='PB5', sck='PB3')

spi_ss = machine.Pin('PB2', Pin.OUT)

spi_ss.high()

GD25Q21_CMD_READ_CHIPID =0x90

GD25Q21_CMD_READ_DATA = 0x03

GD25Q21_CMD_WRITE_PAGE = 0x02

GD25Q21_CMD_ERASE_SECTOR = 0x20

GD25Q21_CMD_WRITE_ENABLE = 0x06

GD25Q21_CMD_WRITE_DISABLE = 0x04

def flash_identify():

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_READ_CHIPID, 0x00, 0x00, 0x00]))

memview = spi.read(2)

spi_ss.high()

return array('B', memview)

def flash_erase(addr):

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_WRITE_ENABLE]))

spi_ss.high()

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_ERASE_SECTOR, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, (addr >> 0) & 0xFF]))

spi_ss.high()

def flash_write(addr, buf):

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_WRITE_ENABLE]))

spi_ss.high()

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_WRITE_PAGE, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, (addr >> 0) & 0xFF]))

spi.write(buf)

spi_ss.high()

def flash_read(addr, cnt):

spi_ss.low()

spi.write(array('B', [GD25Q21_CMD_READ_DATA, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, (addr >> 0) & 0xFF]))

memview = spi.read(cnt)

spi_ss.high()

return array('B', memview)

flash_identify()

flash_erase(0x1000)

time.sleep(2)

flash_read(0x1000, 32)

flash_write(0x1000, array('B', [i for i in range(32)]))

time.sleep(1)

flash_read(0x1000, 32)

API

SPI(id, baudrate, *, polarity=SPI.IDLE_LOW, phase=SPI.EDGE_FIRST, slave=False,

msbf=True, bits=8, mosi=None, miso=None, sck=None, ss=None)

参数

含义

可取值

id

0、1、2、3

baudrate

时钟速率

polarity

时钟极性

IDLE_LOW、IDLE_HIGH

phase

时钟相位

EDGE_FIRST、EDGE_SECOND

slave

是否为从机

msbf

是否先传最高位

bits

数据位宽

取值8--32

mosi

SPI_MOSI引脚

miso

SPI_MOSI引脚

sck

SPI_SCK引脚

ss

SPI_SS引脚,从机模式下使用

baudrate([int])

获取或设置波特率

write(data): count

只写;data可以是一个整数,或实现buffer协议的对象(如str、bytearray、array.array)

read(count): int or buf

readinto(buf): count

只读;读取一个数据时返回一个整数,读取多个数据时返回一个memoryview

write_read(data): int or buf

write_readinto(wbuf, rbuf)

同时读写;参数同'write',返回值同'read'

I2C

通用读写

import machine, time

from machine import I2C

from array import array

i2c = machine.I2C(0, 100000, sda='PA4', scl='PA5')

i2c.scan()

SLV_ADDR = 0x50 # AT24C02的地址

i2c.writeto(SLV_ADDR, array('B', [0x00, 0x37, 0x55, 0xAA, 0x78]))

time.sleep(1)

i2c.writeto(SLV_ADDR, array('B', [0x00])) # dummy write, set read address

i2c.readfrom(SLV_ADDR, 4)

存储读写

i2c.mem_writeto(SLV_ADDR, 0x10, array('B', [0x37, 0x55, 0xAA, 0x78]))

time.sleep(1)

i2c.mem_readfrom(SLV_ADDR, 0x10, 4)

API

I2C(id, baudrate, *, slave=False, slave_addr=None, scl=None, sda=None)

参数

含义

可取值

id

0、1、2

baudrate

时钟速率

slave

是否为从机

True、False

slave_addr

从机地址,从机模式下使用

scl

I2C_SCL引脚

sda

I2C_SDA引脚

baudrate([int])

获取或设置波特率

scan(start=0x10, end=0x7F): tuple

扫描 I2C 总线上的从机

writeto(addr, data): count

data可以是一个整数,或实现buffer协议的对象(如str、bytearray、array.array)

readfrom(addr, count): str

readfrom_into(addr, buf): count

读取

mem_writeto(addr, memaddr, data, memaddr_len=1): count

data可以是一个整数,或实现buffer协议的对象(如str、bytearray、array.array)

memaddr_len是memaddr的长度,单位为byte

mem_readfrom(addr, memaddr, count, memaddr_len=1): str

mem_readfrom_into(addr, memaddr, buf, memaddr_len=1): count

从指定存储地址读取

ADC

软件启动

import machine

from machine import ADC

adc = machine.ADC(0, chns=[0, 1, 2])

adc.start()

while adc.busy(): pass

adc.read(0)

adc.read(1)

adc.read(2)

CH0 on PB0、CH1 on PB1、...、CH15 on PB15

定时启动

adc = machine.ADC(0, chns=[1], trigger=ADC.TRIG_TIMER3)

tmr = machine.Timer(3, 1000, trigger=Timer.TO_ADC) # 1000us

tmr.start()

buf = [0] * 500

for i in range(500):

while not adc.any(1): pass

buf[i] = adc.read(1)

API

ADC(id, chns, *, samprate=1000000, trigger=ADC.TRIG_SW, trigger_pin=None)

参数

含义

可取值

id

0

chns

转换通道

samprate

转换速率

50000-5000000

trigger

启动触发

TRIG_SW、TRIG_FALLING、TRIG_RISING、TRIG_EDGE、TRIG_TIMER0、TRIG_TIMER1、TRIG_TIMER2、TRIG_TIMER3

trigger_pin

外部引脚触发启动时指定触发引脚

samprate([int])

获取或设置转换速率

channel([chns])

trigger([trigger[, trigger_pin]])

获取或设置转换通道

获取或设置启动触发

start()

busy()

any(chn)

read(chn)

软件启动模式下,start()用来启动转换;busy()检测转换是否完成;any()检测指定通道是否有转换结果可读

DAC

输出电平

import machine

from machine import DAC

dac = machine.DAC(0)

dac.write(1/3.3 * 4095)

DAC0 on PB12;DAC1 on PB13

输出波形

import math, array

buf = array.array('H', [0]*250)

for i in range(250):

buf[i] = int(math.sin(2*math.pi/250*i) * 2047 + 2048)

dac = machine.DAC(0, trigger=DAC.TRIG_TIMER2, data=buf)

tmr = machine.Timer(2, 1000, trigger=Timer.TO_DAC) # 1000us

tmr.start()

指定波形数据输出完后需要重新调用 dma_write() 更新波形数据

API

DAC(id, *, trigger=DAC.TRIG_WRITE, data=None)

参数

含义

可取值

id

0、1

trigger

输出更新触发

TRIG_WRITE、TRIG_FALLING、TRIG_RISING、TRIG_TIMER0、TRIG_TIMER1、TRIG_TIMER2、TRIG_TIMER3

data

用于非TRIG_WRITE触发时

write(int)

使DAC输出指定电平,只有当“trigger == TRIG_WRITE”时才能使用此方法

dma_write(buf)

dma_done(): bool

使DAC输出一组电平,只有当“trigger != TRIG_WRITE”时才能使用此方法

dma_write(buf)设置数据输出完成后,dma_done()返回true,需要重新调用 dma_write() 更新波形数据

PWM

共4路PWM,前两路PWM0、PWM1是BPWM,后两路PWM2、PWM3是EPWM

BWPM:1个计数器、6个比较器,6路输出,同频、占空比可不同

EPWM:6个计数器、6个比较器,6路输出,可组合成3路互补输出

BWPM

import machine

from machine import PWM

pwm = machine.PWM(PWM.BPWM0, clkdiv=192, period=1000)

pwm.channel(PWM.CH2, duty=300, pin='PA2')

pwm.channel(PWM.CH3, duty=700, pin='PA3')

pwm.start()

EPWM(独立输出)

pwm = machine.PWM(PWM.EPWM0, clkdiv=192)

pwm.channel(PWM.CH2, period=1000, duty=500, pin='PA3')

pwm.channel(PWM.CH3, period=2000, duty=500, pin='PA2')

pwm.start() or

pwm.start([PWM.CH2, PWM.CH3])

EPWM(互补输出)

pwm = machine.PWM(PWM.EPWM0, clkdiv=192)

pwm.channel(PWM.CH0, period=1000, duty=500, deadzone=25, pin='PA5', pinN='PA4')

pwm.channel(PWM.CH2, period=2000, duty=500, deadzone=25, pin='PA3', pinN='PA2')

pwm.start() or

pwm.start([PWM.CH0, PWM.CH2])

只要参数 deadzone 值不为 None,就设置为互补输出

只有CH0、CH2和CH4可以设置为互补输出,且CH0为互补输出时CH1被用作其互补输出,CH2与CH3、CH4与CH5有相同关系

API

PWM(id, *, clkdiv=192, period=1000)

参数

含义

可取值

id

BPWM0、BPWM1、EPWM0、EPWM1

clkdiv

预分频

1--256

period

周期时长

1--65536

channel(chn, *, duty=500, period=1000, deadzone=None, pin=None, pinN=None)

配置通道

参数

含义

可取值

chn

CH0、CH1、CH2、CH3、CH4、CH5

duty

高电平时长

1--65536

period

周期时长

1--65536

deadzone

死区时长

1--4096 或 None

pin

通道输出引脚

pinN

通道互补输出引脚

start([chns])

stop([chns])

BPWM:无参数

EPWM:无参数时启动/停止所有已配置通道,有参数时启动/停止指定通道

period([period]) # for BPWM

period(chn[, period]) # for EPWM

duty(chn[, duty])

deadzone(chn[, deadzone])

查询或设置周期时间长度、高电平时间长度、死区时间长度

CAN

自测

import machine

from machine import CAN

can = machine.CAN(0, 100000, mode=CAN.LOOPBACK, rxd='PA4', txd='PA5')

can.send(0x137, b'\x11\x22\x33\x44\x55\x66\x77\x88')

while not can.any(): pass

can.read()

将PA4和PA5短接,执行上面的自测代码

接收

can = machine.CAN(0, 100000, rxd='PA4', txd='PA5')

can.filter([CAN.FRAME_STD, 0x137, 0x7FE), (CAN.FRAME_STD, 0x154, 0x7FF), (CAN.FRAME_EXT, 0x1137, 0x1FFFFFFC)])

while not can.any(): pass

can.read()

当消息满足“ID & mask == check & mask”时被接收,因此上面的设置接收ID等于0x137、0x136和0x154的标准帧消息,及ID等于0x1137、0x1136、0x1135和0x1134的扩展帧消息

API

CAN(id, baudrate, *, mode=CAN.NORMAL, rxd=None, txd=None, irq=0, callback=None, priority=4)

参数

含义

可取值

id

0、1

baudrate

位速率

1000-1000000

mode

工作模式

NORMAL、LISTEN、LOOPBACK

rxd

接收引脚

txd

发送引脚

irq

中断触发源

callback

中断回调函数

priority

中断优先级

0--7,数值越小优先级越高

baudrate([int])

获取或设置波特率

full()

send(id, data, *, format=CAN.FRAME_STD, remoteReq=False, retry=True)

full()返回False表示可以发送,send()用于发送数据,参数data可以是一个整数或buffer

any()

read()

any()返回True表示有数据可读,read()用于读出接收到的数据,返回值格式为(format, id, bytes, is_remote)

state()

查询模块当前状态,可取值及其解释如下:

状态

含义

STAT_EACT

ERROR ACTIVE, 1 error_counter < 96

STAT_EWARN

ERROR WARNING, 1 error_counter >= 96

STAT_EPASS

ERROR PASSIVE, 1 error_counter >= 127

STAT_BUSOFF

BUS OFF, 1 error_counter >= 255

filter([filter])

读取或设置接收过滤器,滤波器格式为:[(CAN.FRAME_STD, check11b, mask11b), (CAN.FRAME_EXT, check29b, mask29b)],列表中最多可以有8个滤波器

RTC

rtc = machine.RTC()

rtc.datetime([2020, 5, 11, 0, 14, 34, 00])

rtc.datetime()

datetime()用于查询或设置当前时间,参数依次为:年、月、日、DayOfWeek、时、秒,设置时参数中DayOfWeek可以是任意值,因为代码会自动计算它的正确值

RNG

rng = machine.RNG()

rng.get()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值