- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
About a month ago, there was a discussion asking how to modify the sample of Lesson 9 of PSoC 101.
https://community.infineon.com/t5/PSoC-4/PSoC-101-Lesson-9-Timer-Example/m-p/382634#M43753
The poster's intention seemed to be using a Timer to distinct a short push and a long push for different functions or actions.
Although a Timer can have such capability, for making it more flexible, I suggested to use SysTick,
which also saves a Timer for other usage.
Although CY8CKIT-042 has 2 switches, SW1 is dedicated for RESET, so only SW2 is available for the user function.
This time the poster wanted to have a short push, and a long push of the button.
With a short push, a function will be called immediately and with a long push (or keep pushing),
another function will be called repeatedly in a certain interval.
We could have "Single Click", "Double Clicks", "Triple Clicks"..., too, but let save it for another day 😉
Now, the schematic
Pin_Switch (an input pin with dedicated interrupt)
Pins (Pin assignment)
Tera Term log
At first I pushed the button twice, then pushed and kept for a while.
Then pushed the button three times, then pushed and kept for while, again.
main.c
#include <project.h>
#include <stdio.h>
#define MAX_SW2_DURATION_MS 10000
#define SW2_SHORT_THRESHOLD 1000
volatile long sw2_duration = -1 ;
volatile int sw2_short_flag = 0 ;
volatile int sw2_long_flag = 0 ;
volatile int sw2_held = 0 ;
volatile long sw2_sec_count = 0 ;
volatile long sw2_short_threshold = SW2_SHORT_THRESHOLD ; // New
/* print related utilities */
#define STR_LEN 64
char str[STR_LEN+1] ;
void print(char *str)
{
UART_UartPutString(str) ;
}
void cls(void)
{
print("\033c") ; /* reset */
CyDelay(100) ;
print("\033[2J") ; /* clear screen */
CyDelay(100) ;
}
void splash(char *title)
{
cls() ;
if (title && *title) {
print(title) ;
print(" ") ;
}
snprintf(str, STR_LEN, "(%s %s)\n\r", __DATE__, __TIME__) ;
print(str) ;
}
/* SysTick related functions */
volatile uint32_t tick_count = 0 ;
void set_short_threshold(long new_value) // New
{
sw2_short_threshold = new_value ;
}
CY_ISR(tick_callback)
{
tick_count++ ;
if (sw2_duration >= 0) { // if sw2_duration < 0, this stops
sw2_duration++ ;
if (sw2_duration >= sw2_short_threshold) {
sw2_long_flag = 1 ;
sw2_held = 1 ;
sw2_duration = 0 ;
}
}
}
int find_empty_slot(void)
{
int result = -1 ;
uint32_t i ;
for (i = 0 ; i < CY_SYS_SYST_NUM_OF_CALLBACKS ; i++ ) {
if (CySysTickGetCallback(i) == NULL) {
result = i ;
break ;
}
}
return(result) ;
}
void start_sys_tick_timer(void)
{
int sys_tick_slot = 0 ;
sys_tick_slot = find_empty_slot() ;
if (sys_tick_slot < 0) {
print("Sorry No empty SysTick Slot available\n\r") ;
while(1) { } /* halting here */
} else {
CySysTickStart() ;
CySysTickSetCallback(sys_tick_slot, tick_callback) ;
}
}
CY_ISR(sw2_isr)
{
Pin_Switch_ClearInterrupt() ;
if (Pin_Switch_Read()) { /* SW2=High -> released */
if (sw2_held == 0) {
sw2_short_flag = 1 ;
}
sw2_sec_count = 0 ;
sw2_held = 0 ;
sw2_duration = -1 ;
} else { /* SW2=Low -> pushed */
sw2_duration = 0 ;
}
}
void init_hardware(void)
{
/* Enable global interrupts. */
CyGlobalIntEnable;
start_sys_tick_timer() ;
sw2_int_ClearPending() ;
sw2_int_StartEx(sw2_isr) ;
UART_Start() ;
splash("button double assing test") ;
}
int main(void)
{
init_hardware() ;
set_short_threshold(1500) ; // now 1.5 sec is the threshold
for(;;)
{
if (sw2_short_flag) {
sw2_short_flag = 0 ;
print("Button Pushed!\n\r") ;
}
if (sw2_long_flag) {
sw2_long_flag = 0 ;
sw2_sec_count++ ;
snprintf(str, STR_LEN, "%ld\n\r", sw2_sec_count) ;
print(str) ;
}
}
}
At the bottom of the previous discussion,
@Michael_K -san, asked a couple of questions, but as I could not reply to the discussion, let me try to reply here.
(Q1) Is it not possible to replace sw2_duration in the SysTick callback with the tick_count and reset tick_count after SW2_SHORT_TRESHOLD is reached?
I think it is possible, but if we want to use tick_count for other time measure(s),
I'd rather use dedicated variable to keep track of one purpose.
(Q2) And why does sw2_duration have the value -1 in the ISR?
In this example, I assigned three mode(s) on sw2_duration
-1 or negative number:
Counter for SW2 is inactive.
So nothing will be done in the ISR.
0 to sw2 duration: SW2 is in short or first pushed state
If SW2 is released during this state, it will be taken as sw2_short_flag.
sw2 duration or longer : SW2 is in long push state
While in this mode, function for sw2_long_flag is set repeatedly.
BTW, I did not care about overflow of the counter, since long can hold rather large value,
I thought not many will try to keep holding the button for such a long time (more than 20 days!)
moto
- Labels:
-
ispn:39611:1:0
-
l1:314:1:0
-
PSoC4