此帖出自DigiKey得捷技术专区论坛
| ||
|
||
接着在stacks中添加对应的stack,也就是外部中断9和10
配置他们的属性,包括中断名称,触发方式,中断优先级和回调函数
我们新建一个Key_driver.c文件来实现按键的功能。主要就两个对外的接口,一个就是中断的初始化函数。另外一个就是在中断函数中注册回调函数。这样就能实现按键功能的解耦。下面就是该文件的代码。
#include "driver_key.h"
/* KEY 外部中断初始化函数 */
void Key_IRQ_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
/* Open ICU module */
err = R_ICU_ExternalIrqOpen(&g_external_irq9_ctrl, &g_external_irq9_cfg);
err = R_ICU_ExternalIrqOpen(&g_external_irq10_ctrl, &g_external_irq10_cfg);
/* 允许中断 */
err = R_ICU_ExternalIrqEnable(&g_external_irq9_ctrl);
err = R_ICU_ExternalIrqEnable(&g_external_irq10_ctrl);
}
// 注册回调函数的接口
void key_register_callbacks(callback_func_t key0_cb, callback_func_t key1_cb) {
callbacks.key0_cb = key0_cb;
callbacks.key1_cb = key1_cb;
}
// key0 的中断处理函数
void key0_callback(external_irq_callback_args_t *p_args) {
if (callbacks.key0_cb != NULL) {
callbacks.key0_cb();
}
}
// key1 的中断处理函数
void key1_callback(external_irq_callback_args_t *p_args) {
if (callbacks.key1_cb != NULL) {
callbacks.key1_cb();
}
}
static uint8_t Led_frequencyindex = 0;
static uint32_t Led_frequency[] = {10, 300, 500, 1000, 1300};
void my_key0_handler(void) {
Led_frequencyindex = (Led_frequencyindex+1)%5;
}
void my_key1_handler(void) {
if(Led_frequencyindex == 0)
{
Led_frequencyindex = sizeof(Led_frequency)/sizeof(Led_frequency[0]) - 1;
}
else
{
Led_frequencyindex = (Led_frequencyindex-1)%(sizeof(Led_frequency)/sizeof(Led_frequency[0]));
}
}
void blinky_thread_entry (void * pvParameters)
{
FSP_PARAMETER_NOT_USED(pvParameters);
/* LED type structure */
bsp_leds_t leds = g_bsp_leds;
Key_IRQ_Init();
key_register_callbacks(my_key0_handler, my_key1_handler);
/* If this board has no LEDs then trap here */
if (0 == leds.led_count)
{
while (1)
{
; // There are no LEDs on this board
}
}
/* Holds level to set for pins */
bsp_io_level_t pin_level = BSP_IO_LEVEL_LOW;
while (1)
{
/* Enable access to the PFS registers. If using r_ioport module then register protection is automatically
* handled. This code uses BSP IO functions to show how it is used.
*/
R_BSP_PinAccessEnable();
/* Update all board LEDs */
for (uint32_t i = 0; i < leds.led_count; i++)
{
/* Get pin to toggle */
uint32_t pin = leds.p_leds[i];
/* Write to this pin */
R_BSP_PinWrite((bsp_io_port_pin_t) pin, pin_level);
}
/* Protect PFS registers */
R_BSP_PinAccessDisable();
/* Toggle level for next write */
if (BSP_IO_LEVEL_LOW == pin_level)
{
pin_level = BSP_IO_LEVEL_HIGH;
}
else
{
pin_level = BSP_IO_LEVEL_LOW;
}
vTaskDelay(Led_frequency[Led_frequencyindex]);
}
}
打开xshell,通过串口连接。
通过命令4开始执行上面的代码,结果打印在控制台。可以看到OSPI的通信速率要比QSPI快很多。 我尝试了将HIGH_SPEED_MODE定义为0,结果程序卡死了。
/**初始化DAC*/
fsp_err_t common_init(void)
{
fsp_err_t fsp_err = FSP_SUCCESS;
fsp_err = R_DAC_Open(&g_dac0_ctrl, &g_dac0_cfg);
fsp_err = R_DAC_Start(&g_dac0_ctrl);
fsp_err = adc_initialize();
....
}
/**初始化ADC*/
static fsp_err_t adc_initialize(void)
{
fsp_err_t fsp_err = FSP_SUCCESS;
fsp_err = R_ADC_Open (&g_adc_ctrl, &g_adc_cfg);
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
fsp_err = R_ADC_ScanCfg (&g_adc_ctrl, &g_adc_channel_cfg);
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
fsp_err = R_ADC_ScanStart (&g_adc_ctrl);
if (FSP_SUCCESS != fsp_err)
{
return fsp_err;
}
/* Read TSN cal data (value written at manufacture, does not change at runtime) */
//fsp_err = R_ADC_InfoGet (&g_adc_ctrl, &g_adc_info_rtn);
return fsp_err;
}
uint16_t Read_ADC_Voltage_Value(void)
{
uint16_t adc_data;
(void)R_ADC_ScanStart(&g_adc_ctrl);
while (!scan_complete_flag) //等待转换完成标志
{
;
}
scan_complete_flag = false; //重新清除标志位
/* 读取通道0数据 */
R_ADC_Read(&g_adc_ctrl, ADC_CHANNEL_0, &adc_data);
return adc_data;
}
void gpt_blue_callback(timer_callback_args_t * p_args)
{
/* Void the unused params */
FSP_PARAMETER_NOT_USED(p_args);
double angle = 2 * M_PI * i / TABLE_SIZE;
double sine_value = sin(angle);
int mapped_value = (sine_value + 1.0) * 0.5 * MAX_VALUE;
R_DAC_Write(&g_dac0_ctrl, mapped_value);
i = (++i)%TABLE_SIZE;
SEGGER_RTT_printf(0, "adcvalue :%d\r\n",Read_ADC_Voltage_Value());
.....
}
typedef struct menu_fn_tbl
{
char_t * p_name; /*<! Name of Test */
test_fn ( * p_func)(void); /*<! Pointer to Test Function */
} st_menu_fn_tbl_t;
/* Table of menu functions */
static st_menu_fn_tbl_t s_menu_items[] =
{
{"Kit Information" , kis_display_menu},
{"Web Server" , eth_emb_display_menu},
{"Network Name Lookup" , eth_www_display_menu},
{"Quad-SPI and Octo-SPI Speed Comparison" , ext_display_menu},
{"Cryptography and USB High speed (MSC)" , enc_display_menu},
{"Next Steps", ns_display_menu },
{"", NULL }
};
清屏并将光标移至屏幕起始位置。
在一个无限循环中:
将当前ADC值格式化为字符串,并发送到控制台进行显示。
暂停500毫秒,以防止更新速度过快导致显示混乱。
再次清屏并重置光标位置,确保每次更新时数据都在相同的位置显示。
test_fn showADCdata(void)
{
int8_t c = -1;
uint16_t temp[50];
uint8_t i;
uint16_t adcvalue;
sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
/* ignoring -Wpointer-sign is OK when treating signed char_t array as as unsigned */
print_to_console((void*)s_print_buffer);
while(1)
{
sprintf (s_print_buffer, "%s:%d\r\n", "ADC:", g_adcvalue);
print_to_console((void*)s_print_buffer);
sprintf (s_print_buffer, "%s%s", gp_clear_screen, gp_cursor_home);
vTaskDelay(500);
print_to_console((void*)s_print_buffer);
}
return (0);
}
void hal_entry(void)
{
/* TODO: add your own code here */
uint16_t i = 0;
uint16_t j = 0;
uint32_t FlashID = 0;
uint32_t FlashDeviceID = 0;
uint16_t u16temp;
Debug_UART4_Init(); // SCI4 UART 调试串口初始化
printf("hellow world\r\n");
QSPI_Flash_Init(); // 串行FLASH初始化
adc_init();
dac_init();
R_ICU_ExternalIrqOpen(&g_external_irq9_ctrl, &g_external_irq9_cfg);
R_ICU_ExternalIrqOpen(&g_external_irq10_ctrl, &g_external_irq10_cfg);
/* 允许中断 */
R_ICU_ExternalIrqEnable(&g_external_irq9_ctrl);
R_ICU_ExternalIrqEnable(&g_external_irq10_ctrl);
while(1)
{
u16temp = getadcvalue();
writebuf[i++] = u16temp;
printf("line1=%d\r\n",u16temp);
if(i == 1000)
{
i = 0;
QSPI_Flash_Write((uint8_t *)writebuf, 0x000000, 2000);
}
if(readflag == 1)
{
readflag = 0;
QSPI_Flash_BufferRead((uint8_t *)readbuf,0x000000,2000);
for( j = 0; j<1000; j++)
{
printf("line2=%d\r\n",readbuf[j]);
}
}
R_BSP_SoftwareDelay(1,BSP_DELAY_UNITS_MICROSECONDS);
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
// key0 的中断处理函数
void key0callback(external_irq_callback_args_t *p_args) {
if(get_wave_type() == WAVE_SINE)
{
set_wave_type(WAVE_SQUARE);
}
else
{
set_wave_type(WAVE_SINE);
}
}
// key1 的中断处理函数
void key1callback(external_irq_callback_args_t *p_args) {
readflag = 1;
}
uint8_t amplitude_index;
// key2 的中断处理函数
void key2callback(external_irq_callback_args_t *p_args) {
set_wave_amplitude(amplitude_index++);
amplitude_index = amplitude_index%4;
}
uint32_t g_frequency = 500;
// key3 的中断处理函数
void key3callback(external_irq_callback_args_t *p_args) {
set_wave_frequency(g_frequency);
g_frequency+=200;
g_frequency = g_frequency%1500;
}
初始化外设,包含以下这些外设:
初始化uart4,用于输出调式信息和用于输出ADC波形。
初始化QSPI,主要用于存储历史波形,存储的数据为adc采集到的波形。
初始化DAC,用于输出0-3.3v的自定义波形,设置的波形目前只有正弦波和方波。
初始化ADC,由于手头没有示波器工具,只能使用板载的ADC,由于测试使用ADC的功能在主函数中实现,采样率只有勉强1khz。
开启外部中断,实现按键功能,用于调整波形和输出历史波形。
开启一个1ms执行一次的循环,实现的功能如下:
获取ADC采样的数据,adc的值存储在一个全局变量中。
将ADC的值存储到一个数组中,当数组存了大概1s的数据后,存储到外部flash中,该过程可能比较耗时,因为擦除这个过程花费很多时间,会稍微影响其他任务,但不影响DAC的波形输出。
如果检测到读取历史波形的按键按下,会读取flash中的数据,并打印出来。
volatile uint32_t timer_ticks = 0; // 用于计数定时器中断次数
uint32_t wave_frequency = 1000; // 波形频率,默认1kHz
uint64_t pclkd_freq_hz //时钟频率
uint16_t wave_amplitude = 2048; // DAC最大值
WaveType current_wave_type = WAVE_SINE; // 默认为正弦波
uint16_t dac_value = 0;
// 定时器中断回调函数
void dac_timercallback(timer_callback_args_t * p_args) {
FSP_PARAMETER_NOT_USED(p_args);
switch (current_wave_type) {
case WAVE_SINE:
// 正弦波的计算
dac_value = (wave_amplitude * (1 + sin(2 * M_PI * timer_ticks / wave_frequency))) / 2;
break;
case WAVE_SQUARE:
// 方波的计算
dac_value = (timer_ticks < wave_frequency / 2) ? wave_amplitude : 0;
break;
}
R_DAC_Write(&g_dac0_ctrl,dac_value);
timer_ticks++;
if (timer_ticks >= wave_frequency) {
timer_ticks = 0;
}
}
// 设置波形频率
void set_wave_frequency(uint32_t freq) {
// 重新配置定时器以适应新的频率
uint32_t period_counts =(uint32_t) (((uint64_t) pclkd_freq_hz ) / freq)-1;
// 这里需要根据实际使用的定时器进行相应的配置
R_GPT_PeriodSet(&dac_timer_ctrl, period_counts);
}
// 设置波形幅值
void set_wave_amplitude(Amplitude amp) {
switch(amp)
{
case AMP_500:
wave_amplitude = 500;
break;
case AMP_1500:
wave_amplitude = 1500;
break;
case AMP_2500:
wave_amplitude = 2500;
break;
case AMP_3500:
wave_amplitude = 3500;
break;
}
}
// 设置波形类型
void set_wave_type(WaveType type) {
current_wave_type = type;
}
WaveType get_wave_type(void) {
return current_wave_type;
}
根据用户选择的波形计算DAC输出值
正弦波
set_wave_frequency:设置波形,主要利用R_GPT_PeriodSet接口来设置定时器的周期,通过R_FSP_SystemClockHzGet接口可以获取定时器的时钟频率,利用时钟频率和需求的定时器频率就可以计算出定时器的溢出值。
set_wave_amplitude:设置幅值,这部分简单,调整wave_amplitude变量就能实现DAC波形的变化。
set_wave_type:设置波形的类型,即用以输出正弦波和方波。
uint16_t getadcvalue(void)
{
return g_adcvalue;
}
void g_adc0_callback(adc_callback_args_t * p_args)
{
FSP_PARAMETER_NOT_USED(p_args);
R_ADC_Read(&g_adc0_ctrl, ADC_CHANNEL_0, &g_adcvalue);
(void)R_ADC_ScanStart(&g_adc0_ctrl);
}
EEWorld Datasheet 技术支持